spring高级装配
- profile
- 使用背景:当程序在不同的开发阶段,要用到不同的开发配置时,需要用到不同的bean,这个时候就需要profile来规定运行时需要哪个bean
- 使用场景:在运行的时候根据环境确定创建哪个bean和不创建哪个bean
- 使用方法:将某个bean定义整理到一个或者多个profile中,部署的时候确保相应的profile处于激活状态。
- 配置profile bean
- 可以用@Profile指定某个bean属于哪个profile
- 示例
- 只有在dev profile激活时才会创建这个bean
- 注1:注解开发profile@Profile作用在了类上,告诉Spring这个配置类中的bean只有在dev profile激活时才创建 dev profile没有被激活的话,@Bean的注解都会被忽略掉。
- 注2:Spring3.1中,只能在类级别上使用@Profile注解,在Spring3.2开始,你也可以在方法级别上使用@Profile注解,与@Bean注解一同使用,这样的话就能将两个bean放置到同一个配置类中。 尽管只有当规定的profile被激活时,相应的bean才会被创建,但是可能会有其他的bean并没有声明在一个给定的profile中。没有指定profile的bean始终都会被创建,与激活哪个profile没有关系。
- 在xml中配置profile
- 第一种方法:为每一个profile配置一个xml文件,不提倡的做法
- 示例:
- 第二种方法:将所有的profile都放在同一个xml中
- 示例如下:
- 注:两个bean的id都一样在创建的时候只会创建一个看激活哪一个。
- 第一种方法:为每一个profile配置一个xml文件,不提倡的做法
- 可以用@Profile指定某个bean属于哪个profile
- 激活profile
- 注意两个独立的属性
- spring.profiles.active
- 用来设置激活那个profile bean
- spring.profiles.default
- 当没有设置spring.profiles.active的时候会查找这个值,确定激活
- 注:当两个值都没有设定的时候,只会创建普通的bean
- spring.profiles.active
- 激活方法
- a.作为DispatcherServlet的初始化参数
- b.作为Web应用的上下文参数(web.xml)
- 注:比较实用,用来配置所有的默认情况下的profile bean方便开发人员应用,在测试或部署的时候只需要激活响应的bean就可以。激活多个中间用,隔开。
- 实例:
- c.作为JNDI条目
- d.作为环境变量
- e.作为JVM的系统属性
- f.在集成测试类上,使用@ActiveProfiles注解设置
- 实例:
- 注意两个独立的属性
- 条件化bean
- 应用场景
- 希望一个或者多个bean在应用的类库下包含特定的库时创建,或希望在某个bean也声明了之后才创建。
- 实现方法
- 用注解@conditional,可以用在带@bean的方法上
- 给定条件计算结果为true时创建bean,否则不创建
- 实例:
- 配置bean
- 设置给conditional的类需实现condition接口,即参与判定的类必须实现condition接口
- matches方法的两个重要参数
- ConditionContext功能如下
- 借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;
- 借助getBeanFactory()返回的ConfigurableListableBeanFactory 检查bean是否存在,甚至探查bean的属性;
- 借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么;
- 读取并探查getResourceLoader()返回的ResourcesLoader 所加载的资源;
- 借助getClassLoader()返回的ClassLoader加载并检查类是否存在。
- AnnotatedTypeMetadata功能
- 检测带有@Bean的方法上还有什么其他的注释
- AnnotatedTypeMetadata也是一个接口
- ConditionContext功能如下
- 从spring4开始@profile注解进行了重构,基于@conditional和condition实现
- 实现@profile
- ProfileCondition的实现
- 处理@profile的流程
- 我们可以看到,ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile注解的所有属性。借助该信息,他会明确地检查value属性,该属性包含了bean的profile名称。然后根据ConditionContext得到的Environment来检查【借助acceptsProfiles()方法】该profile是否处于激活状态。
- 应用场景
- 处理自动装配的歧义性
- 应用场景
- 自动依赖注入的时候,依赖的是一个接口实现类的对象,这个接口可能拥有多个实现类,并且这些实现类都已经实例化为bean,这个时候spring就不能选择要注入哪一个bean,因此出现了注入歧义
- 解决方法
- 表示首选bean
- 使用默认的限定标识符(默认的标识符为bean的ID)
- 用@Primary
- 使用自动装配
- 使用java配置
- 只用xml
- 缺陷
- 当两个或两个以上的bean被标记为首选,出现歧义的时候就不能正确的判断。
- 用@Primary
- 使用默认的限定标识符(默认的标识符为bean的ID)
- 限定自动装配的bean
- 创建自定义的限定符
- 使用默认的限定符,默认的限定符是bean的ID
- 方法
- 缺点:当代码重构后,换了类名,就找不到相应的bean
- 创建自定义的限定符
- 创建
- 使用
- 使用默认的限定符,默认的限定符是bean的ID
- 使用自定义的限定符注解
- 使用场景
- 当多个bean有相同的特性,即拥有相同的限定符。spring不允许叠加多个@Qualifier(" ").因为注解本身没有带有@Repeatable注解
- 创建自定义的限定符注解
- 使用自定义的限定符注解,在注入的时候应用相应的注解准确注入
- 自定义注解的方法就是:将已有的注解进行组合,如上面定义自定义的限定符注解一样
- 使用场景
- 创建自定义的限定符
- 表示首选bean
- 应用场景
- bean的作用域
- 单例(singleton):
- 在整个应用中,只创建bean的一个实例
- 是默认的作用域,所有的依赖都用的是一个bean,缺点是当bean变化时得不到原来的bean
- 原型(prototype):
- 每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例
- 使用方法
- 自动创建
- java配置类
- xml
- 会话(Session):在Web应用中,为每个会话创建一个bean实例
- 使用场景
- 网上商城项目中,购物车bean,既要保持相对的独立,又必须保持在一个会话中是同一个。
- 使用方法
- 方法一:
- 方法二:默认情况下是用CGLib创建目标类代理,可以使用第二张图的方法关闭
- 解释proxyMode
- 理解:见名知意,是一个规定代理模型,解决将会话或者请求bean注入到单例bean中遇到的问题
- 问题场景:当需要将会话或请求bean注入到单例bean中的时候,单例bean会在spring上下文加载的时候创建,并注入相应的依赖,但是请求和会话bean是在运行的时候才会创建的。并且注入的bean要是特定用户的会话bean。
- 解决办法:spring会注入一个会话或请求bean的代理,当用户建立会话时,代理会对其进行依赖解析调用委托给挥霍啊作用域内真正的bean。
- 注:这里ScopedProxyMode.INTERFACES表明代理要实现的是一个被确切bean实现了的接口,如果代理要实现的是一个具体的类,则必须是用CGLib来生成基于类的代理,并且将proxyMode设为ScopeProxyMode.TARGET_CLASS
- 使用场景
- 请求(Request):在Web应用中,为每个请求创建一个bean实例
- 单例(singleton):
- 运行是值注入
- 产生的原因
- 避免硬编码
- 方法一:属性占位符
- 方法二:spring表达式语言(SpEL)
- 注入外部的值
- 方法步骤:声明属性源,通过spring的environment检索属性
- 深入理解Environment,getProperty方法的四种变形
- a、String getProperty(String key)
- b、String getProperty(String key,String defaultValue)
- 当属性不存在时使用默认值
- c、T getProperty(String key,Class type)
- 获取一个类对象,并非完全字面量
- d、T getProperty(String key,Class type,T defaultValue)
- e、String[] getActiveProfiles() :返回激活profile名称的数组
- f、String[] getDefaultProfiles():返回默认profile名称的数组
- g、boolean adcceptsProfiles(String...profiles):如果environment支持给定profile的话,就返回true
- h、getRequiredProperty(String key):属性必须存在,不存在会报错
- i、getPropertyAsClass():将属性解析为类
- 解析属性占位符
- 占位符
- 将属性定义到外部的属性文件,用占位符值将其插入到spring bean中
- ${....}
- 使用前提
- 配置PropertyPlaceholderConfigurer bean或PropertySourcesPlaceholderConfigurer bea(从3.1开始推荐使用)
- 在java中配置
- 在xml中配置
- 实例应用xml
- <bean id="sgtPeppers" class="soundsystem.BlankDisc" c:_title="${disc.title}" c:_artist="${disc.artist}" />
- 使用组件扫描和自动装配,用@value注解
- 占位符
- 使用spring表达式语言进装配(SpEL)
- 使用格式
- #{........}
- 用法功能
- a、使用bean的ID来引用bean;
- b、调用方法和访问对象的属性;
- c、对值进行算数、关系和逻辑运算;
- d、正则表达式匹配;
- e、集合操作。
- 特殊的运算符
- “?.”比“.”更加强大,能够在调用前判断对象是否存在,不存在抛出异常
- T():结果是一个class对象
- 例:T(java.lang.Math).PI
- ? :
- 第一种用法,和普通的三元运算符一样
- 第二种用法,判断是否为null,如果为null使用默认的值 #{disc.title ?: 'rettle and hum'} 如果前面的title不存才用后面的字符串替换
- matches
- 用法:计算给定的值是否与正则表达式匹配,返回true或false
- 用例:#{admin.email matches '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-+\\.com]'}
- 计算集合
- [ ] 用来从集合或数组中按照索引获取元素
- #{jukebox.songs[4].title}
- #{'This is a test' [3]}
- '.?[ ]' 用来查询,将匹配到的查询项放到一个集合中
- #{jukebox.songs.?[artist eq 'Aeronsmith']}
- '.^[ ] '和'.$[ ]'用来在集合中查询第一个匹配项和最后一个匹配项
- '.![ ]' 用来从集合的每一个成员中选择特定的属性放到另一个集合中,即抽取特定值,查看集合中存储的类型都有哪些
- [ ] 用来从集合或数组中按照索引获取元素
- 使用格式
- 方法步骤:声明属性源,通过spring的environment检索属性
- 产生的原因