从零开始的spring 之 优雅的装配一个bean。

来源:互联网 发布:plc与dcs编程的区别 编辑:程序博客网 时间:2024/05/23 19:18

一、条件化装配bean

spring提供了 很多灵活的装配方式。这些灵活的方式如果特别熟的话会变得相当便利。

   spring4 引入了一个新的注解 @Conditional  该注解可以放在加有@Bean 的方法上  判断该@Conditional给定的条件是否为true 则spriing 是否创建该bean

该注解 给定了一个class值,给定的类 需要实现一个接口 Condition

public class TestCondition implements Condition{public boolean matches(ConditionContext arg0, AnnotatedTypeMetadata arg1) {return false;}}
实现该接口的matches方法 

 返回值是boolean 如果boolean是true 则创建 加注解的bean 

该方法有两个参数 这两个参数 各种棒。

第一个 ConditionContext 

可以借助 getRegistry() 返回BeanDefinitionRegistry检查bean定义

借助getBeanFactory() 返回的ConfigurableListtableBeanFactory 检查bean 是否存在 并且探查bean的属性。,

借助getEnvironment() 返回的Enviroment 检查某环境变量 是否存在 以及存在它的什么值。 (66666)

借助getResourceLoader() 返回的ResourceLoader 探查加载的资源

借助getLCassLoader() 返回的ClassLoader 加载并检查类是否存在。

第二个 AnnotatedTypeMetadata

 boolean isAnnotated(String type) 判断某注解是否存在于加@Condition 的方法上

boolean b = antm.isAnnotated("org.springframework.context.annotation.Bean");if(b){Map<String,List<Object>> att = antm.getAllAnnotationAttributes("org.springframework.context.annotation.Bean");antm.getAllAnnotationAttributes(annotationType, classValuesAsString)antm.getAnnotationAttributes(annotationType);antm.getAnnotationAttributes(annotationType, classValuesAsString)}return true;

剩下的方法看名字应该知道是什么了 不多说。 用到再看也不迟。 获取其他注解 携带的属性。

二、处理spring装配bean的歧义。

歧义: 举个例子 比如三个bean 同时实现一个接口  在注入参数那声明的是接口 则spring 就无法处理这种情况 抛出异常。

我想过,这地方可以用来 在一个大项目下进行更加简便更加灵活的单元测试。

比如 逻辑和原有代码不同 但是改动很大,或者需要多个组件改动之后相互结合。这个时候 在原先代码基础上改不如重新写一个。  

可以利用接下来说的 让spring注入的 是自己写的新组件。

介绍一个注解: @Primary放在bean上 表示 该bean 如果出现歧义性的时候 会被优先选择。

可以放在加@Bean 的方法上 

可以放在 加@Component  的类上。

可以在xml bean 标签上 声明属性 primary=true

注意 该注解 只能标识一个优先的可选方案  

介绍另一个注解:  @Qualifier 别名注入

加注入方法上或者字段上 然后给定value值 表明根据别名注入

@Qualifier("qwer")

则选择别名为qwer 的 bean 注入。

bean如果没有被指定别名 则 类名首字母小写 即为别名。‘’

如指定一个bean的别名

1、 加载类上 与@Component协作使用

2、加载returnbean方法上 与@Bean 协作使用.

三、关于bean的作用域

默认情况下 spring创建的所有的bean都是单例的 但是在实际生产过程中我们不得不用到多例的情况 ,我最熟知的是struts 和spring 进行整合的时候

struts 要声明成多例的。

spring 定义了很多中作用域:

单例 、原型(多例) 、 会话 、请求

字面意思上去理解。

可以使用@Scope注解来声明作用域 在xml当中 的bean 标签上加scope属性也可以。

可以放在@Component 和@Bean 下。  

@Scope(ConfigurableBeanFactory<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">...)</span>

这个ConfigurableBeanFactory中的字符串常量。 看意思选择即可。

另外session域和request域在WebApplicationContext里面

有一个需要注意的一点:

当不同作用域的bean 相互注入存在的问题

比如 当一个会话级别的bean 被声明注入到单例bean当中

则这个单例bean 将会在类加载阶段就搜索会话级别的bean 但是这个bean在请求未进来之前是不会创建的 

spring为解决这种情况 在 @Scope注解当中提供了一个proxyMode属性  

利用 代理的方式 。 在单例bean创建需要session bean的时候 spring为session级别的bean 创建一个代理对象  

先给其注入代理对象 当这个单例bean 用到sessionbean的方法的时候 将这个调用委托出去 交给真实的bean 

@Bean()@Conditional(TestCondition.class)@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE,proxyMode=ScopedProxyMode.INTERFACES)public SpringTestBean getSpringTestBean(SpringTestBean2 springTestBean2){SpringTestBean bean = new SpringTestBean();bean.setSpringTestBean2(springTestBean2);return bean;}

利用的则是ScopedProxyMode的常量 都知道 创建代理的方式有两种 区分。有接口 和没接口

上面这个是接口的情况,类的话用这个

proxyMode=ScopedProxyMode.TARGET_CLASS

在xml当中 则是 在bean标签里面 使用 <aop:scoped >标签

内有属性 proxy-target-class=  true 表示使用class  false 表示使用interface。


0 0