当前位置: 首页 > news >正文

spring实战第四版01

spring自带了很多容器的实现,,总的分为两类:

  • bean工厂 : 基本的DI支持
  • ApplicationContext: 应用上下文,,应用框架级别的服务,,有更多的特性,比如属性文本解析,事件发布
    • AnnotationConfigApplicationContext
    • AnnotationConfigWebApplicationContext
    • ClassPathXmlApplicationContext
    • FileSystemXmlApplication
    • XmlWebApplicationContext
spring生命周期

在这里插入图片描述

  1. 实例化
  2. 填充属性
  3. 调用BeanNameAware的setBeanName()方法,,如果bean实现了BeanNameAware,,那么spring就会将bean的id传递给setBeanName()方法作为参数
  4. 调用BeanFactoryAware的setBeanFactory()方法,,,可以感知BeanFactory
  5. 调用ApplicationContextAware的setApplicationContext()方法,,,可以感知ApplicationContext
  6. 调用BeanPostProcessor的预初始化方法,,如果实现了这个接口,,就会去调他的postProcessBeforeInitialization()方法
  7. 调用InitializingBean的afterPropertiesSet()方法:spring将调用他们的afterPropertiesSet()方法,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 调用自定义初始化方法 init-method
  9. 调用BeanPostProcessor的初始后方法,,spring将调用postProcessAfterInitialization方法,初始化后方法
  10. bean可以使用了
  11. 容器关闭
  12. 调用Disposable的destroy()方法,,如果bean使用destroy-method声明了销毁方法,同样也会调用
  13. 调用自定义销毁方法 destroy-method
  14. 结束
自动化装配

spring中可以自己注册bean,但是一般都是自动化装配的,,spring中的自动化装配有两种方式:

  • 组件扫描 component scanning:spring会自动发现应用上下文中所创建的bean
  • 自动装配 autowiring: spring会自动满足bean之间的依赖

组件扫描默认不启用: 需要配置@ComponentScan。。或者xml配置<context:component-scan>

spring中测试
   <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.1.12</version></dependency>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public class DemoTest {@AutowiredUser user;@Testpublic void test(){System.out.println("user = " + user);}
}
  • @ContextConfiguration(classes=TestConfig.class) : 这个可以自定义测试的配置文件,手动指定xml/Java config,,主要用于传统的spring项目测试,,非boot
  • @SpringBootTest : 自动加载@SpringBootApplication
spring中bean的装配

bean的装配分为两种:

  1. 隐式的装配
  2. 显示的装配
隐式的装配

@ComponentScan的属性

  • basePackage
  • baskPackageClasses : 设置的数组中包含了类,,这些类所在的包,,会作为组件扫描的基础包,可以创建一个用来扫描的空标记接口(marker interface)

@Autowired

@Autowired这个注解不仅能用在构造器上,还能用在setter方法上,,并且能用在类的任意方法上,spring都会尝试满足方法参数上所声明的依赖,,,如果没有bean会报错,,如果不能确定唯一的bean也会报错,,,,
@Autowired的属性:
- required : 设置为false,找不到不会报错,,但是在启动的时候就发现不了错误了,,执行到那一块代码可能会因为没有注入对象而空指针

@Autowired@Inject,在大多数场景下,,可以互换
@Inject:这个注解来源于 Java依赖注入规范,,该规范同时还定义了@Named注解,,
@Named注解 和 @Component,在大多数场景下,可以互换

但是这种打注解注入的方式,,注入不了第三方组件,,,就需要显示的装配,,,

显示的装配

显示的装配可以用java或者 xml来装配
xml装配bean,,如果不给id,,系统默认会使用全限定类名#0 ,,就是全限定类名+序号,,如果是第一个就是#0,如果有多个,,序号往后累加


@Primary 和 限定符Qualifier(想要注入bean的id)

Environment

PropertySourcesPlaceholderConfigurer: 这个类的对象,能够基于spring environment及其属性源来解析占位符

@PropertySource("classpath:db.properties"): 这个注解会将这个配置加载到spring的Environment中

@Configuration
// 这个属性文件会加载到spring的Environment中,,,
@PropertySource("classpath:db.properties")
public class ExpressiveConfig {@AutowiredEnvironment env;//?????@Value("#{systemProperties['db.username']}")private String username;@Value("#{T(System).currentTimeMillis()}")private Long time;@Beanpublic DataSource dataSource(){System.out.println("username = " + username);System.out.println("time = " + time);String url = env.getProperty("db.url");System.out.println("env.getProperty(\"db.url\") = " +url);Integer age = env.getProperty("user.age", Integer.class, 30);System.out.println("age = " + age);Integer age02 = env.getProperty("user.age02", Integer.class, 30);System.out.println("age02 = " + age02);// 检测某个属性是否存在boolean b = env.containsProperty("user.age02");System.out.println("b = " + b);// 返回激活的profileString[] activeProfiles = env.getActiveProfiles();// 默认的profileString[] defaultProfiles = env.getDefaultProfiles();System.out.println("activeProfiles = " + Arrays.toString(activeProfiles));System.out.println("defaultProfiles = " +  Arrays.toString(defaultProfiles));// 是否支持某个profileboolean b1 = env.acceptsProfiles("prod");System.out.println("b1 = " + b1);DataSource ds = new DataSource();ds.setUrl(url);return ds;}
}

env.acceptsProfiles('prod') : 检测环境中是否有 prod的profile

profile多环境切换

spring.profiles.activespring.profiles.default ,如果没有设置spring.profiles.active那么spring会查找spring.profiles.default的值,,,如果这两个都没有设置,那么spring只会创建那些没有定义在profile中的bean,,,,这两个属性都是复数,,可以激活多个profile,,,列出多个profile,逗号分隔

多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数
  • 作为web应用的上下文参数
  • 作为JNDI条目
  • 作为环境变量
  • 作为JVM的系统属性
  • 在集成测试类上,使用@ActiveProfiles注解设置
@Conditional

profile底层是@Conditional,

public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return false;}
}

这个方法里面的参数是:

  • ConditionContext

    这个是个容器,,可以获取一些对象。比如:

    • BeanDefinitionRegistry : 可以用来检查bean定义
    • ConfigurableListableBeanFactory : 可以用来检查bean是否存在,检查bean的属性
    • Environment : 可以用来检查环境变量是否存在,,以及环境变量对应的值
    • ResourceLoader : 返回ResourceLoader所加载的资源
    • ClassLoader : 可以用来加载并检查类是否存在
  • AnnotatedTypeMetaddata : 能够让我们检查到,,带有@Bean注解的方法上,,还有什么其他的注解

scope的作用域

spring默认的作用域是singleton,同一个实例,,但是有些时候,,你所使用的类是易变的mutable,,他们可能会保持一些状态,,,,因此,重用是不安全的

scope作用域:

  • 单例singleton : 整个应用中,只创建bean的一个实例
  • 原型prototype : 每次注入或者通过spring应用上下文获取的时候,都会创建一个新的bean实例
  • 会话session: 在web应用中,为每个会话创建一个bean实例
  • 请求request: 在web应用中,为每个请求创建一个bean实例
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope("prototype")

商城中,如果购物车对象是单例的话,那么会导致所有用户都会向同一个购物车添加商品,,,另一方面,如果购物车是原型作用域,,那么在应用中某一个地方往购物车中添加商品,在应用的另一个地方可能就不可用了,,prototype总是获取一个新的bean

所以购物车用会话作用域,是最为合适的:


// proxyMode = ScopedProxyMode.INTERFACES : 这个属性解决了 将会话或者请求作用域的bean注入到单例bean中所遇到的问题
@Scope(value= WebApplicationContext.SCOPE_SESSION,proxyMode = ScopedProxyMode.INTERFACES)

为什么要添加这个???proxyMode = ScopedProxyMode.INTERFACES,,因为spring默认是单例的,,如果一个类中@Autowired注入了这个 session作用域的bean,,,而session作用域的bean,只会在用户访问应用之后才会生成,,容器初始化的时候,是没有这个bean的,,所以会报错,,,配置了
proxyMode=ScopedProxyMode.INTERFACES之后,,spring不会直接创建 ShoppingCart实例,,而是会注入一个 ShoppingCart的代理,,这个代理会暴露跟 ShoppingCart一样的方法,,,当用户访问系统后,,,代理会对其进行懒解析,,,并将调用委托给真正的ShoppingCart的Bean

如果这个ShoppingCart是接口就使用proxyMode=ScopedProxyMode.INTERFACES
如果这个ShoppingCart是一个具体的类,,spring就会使用cglib生成基于类的代理,,就使用proxyMode=ScopedProxyMode.TARGET_CLASS,来表明要以生成目标类扩展的方式创建代理

在这里插入图片描述

spring的运行时求值

spring提供了两种在运行时求值的方式:

  • 属性占位符 Property placeholder
  • spring表达式语言 SpEL : spring expression language
spring表达式特性
  • 使用bean的id来引用bean
  • 调用方法和访问对象的属性
  • 对值进行算数,关系,和逻辑运算
  • 正则表达式匹配
  • 集合操作

SpEL需要放到#{...}之中,,属性占位符需要放到${...}之中
用法:

  • #{beanId.属性名字} : 获取指定id的bean的属性值
  • #{systemProperties['user.age']} : 通过systemProperties对象引用系统属性
  • T(java.lang.Math): 在SpEL中访问类作用域的方法和常量的话,,使用T(),比如T(System).currentTimemillis()

使用场景:

  • spring security的安全限制规则
  • thymeleaf模板中使用SpEL表达式引用模型数据

相关文章:

  • YOLOv11助力地铁机场安检!!!一键识别刀具
  • 机器学习与深度学习5:pytorch前馈神经网络FNN实现手写数字识别
  • Python Day34
  • 时代变了,我选择ApiFox替代Postman
  • Nacos集群
  • Wave Terminal + Cpolar:SSH远程访问的跨平台实战+内网穿透配置全解析
  • 熔盐核裂变反应堆:第四代核能技术的重要突破
  • AI时代新词-AI芯片(AI - Specific Chip)
  • 测绘技术重塑低空经济格局
  • 菜鸟之路Day34一一Mybatis-基础操作
  • 泪滴攻击详解
  • 解决 docker pull镜像失败
  • java虚拟机
  • 网络原理与 TCP/IP 协议详解
  • Java-ArrayList集合的遍历方式详解
  • UE5 Niagara Advance 学习笔记
  • 【大模型面试每日一题】Day 29:简单介绍一下混合精度训练的技术要点及潜在风险
  • Node.js Path模块路径处理秘籍
  • 小样本机器学习再发力!2025再登Nature正刊
  • 《软件工程》第 9 章 - 软件详细设计
  • 渝北网站建设/媒体网络推广价格优惠
  • php mysql网站开发工资/aso是什么意思
  • 网站官网上的新闻列表怎么做/百度图片搜索入口
  • 小程序电商系统开发/seo服务内容
  • 做网站在线支付系统多少钱/杭州seo泽成
  • 太原网站建设 网站制作/凡科建站和华为云哪个好