spring框架-3
@Configuration
Spring3.0提供了Java配置管理。
Spring3.0为不喜欢使用XML来配置管理Bean的开发者提供了另外一种管理方式,即:使用Java类进行配置管理。
假如有一个类 Chinese 实现了Person 接口,并含有两个成员变量 String name、Axe axe,此 Chinese Bean 如果通过配置文件注入,格式如下:
<bean id="chin"class="com.yuand.Chinese">
<property name="name" value="zhangsan"/>
<property name="axe"ref="steelAxe"/>
</bean>
<bean id="steelAxe" class="com.yuand.SteelAxe"/>
如果开发者不喜欢使用XML配置文件,Spring3.0允许开发者使用Java类进行配置。
上面的XML配置文件可以替换成如下Java配置类。
import org.springframework.beans.factory.annotation.Value:
import org.springframework.context.annotation.Bean;
@Configuration
public class AppConfig {
@Bean(name = "bbb")
public B bb(){
B b = new B();
b.setBName("zhangsan");
return b;
}
@Bean(name = "aaa")
public A aa(){
A a = new A();
a.setAName("lisi");
a.setB(bb()); //ref
return a;
}
}
<context:annotation-config/>
<bean class="com.origin.d702.config.AppConfig"/>
上面的配置文件中使用了Java配置类的三个常用的Spring的Annotation
- @Configuration:用于修饰一个Java配置类。
- @Bean用于修饰一个方法,将该方法的返回值定义成容器中的一个Bean。
- @Value:用于修饰一个Field,用于为该Field配置一个值,相当于配置一个变量。
一旦使用Java配置类来管理Spring容器中的Bean及其依赖关系,此时就需要使用如下方式来创建Spring容器:
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class)
AnnotationConfigApplicationContext类会根据Java配置类来创建Spring容器。该类还提供了一个register方法用于添加Java配置类。
使用Java配置类时,还有如下常用的Annotation。
- @Import:修饰一个Java配置类,用于向当前Java配置类中导入其他Java配置类。
- @Scope:用于修饰一个方法,指定该方法返回的对应的Bean的生命周期。
- @Lazy:用于修饰一个方法,指定该方法返回的对应的Bean是否需要延迟初始化。
- @DependsOn:用于修饰一个方法,指定在初始化该方法对应的Bean之前,先初始化指定的Bean
Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用
域。Spring支持如下5中作用域。
- singleton:单例模式,在整个SpringloC容器中,singleton作用域的Bean将只生成一个实例。
- prototype:每次通过容器的 getBean方法获取 prototype作用域的Bean时,都将生成一个新的Bean实例。
- request:对于一次HTTP请求,request作用域的Bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求Bean,得到的是同一个实例。只有在Web应用中使用Spring时,该作用域才有效。session:对于一次HTTP会话,session作用域的Bean将只生成一个实例,这意味着,在同一次HTTP会话内,程序每次请求该Bean,得到的是同一个实例。只有在Web应用中使用Spring时,该作用域才有效。
- global session:每个全局的HTTPSession对应一个Bean实例。只有在Web应用中使用Spring时,该作用域才真正有效。
比较常用的是singleton和 prototype两种作用域,对于singleton作用域的 Bean,每次请求该 Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为:如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new关键字创建Bean实例,创建完成后就不再跟踪、维护。如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申
请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此prototype作用域的Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建完成可以反复使用。因此尽量避免将Bean设置成 prototype作用域。
Spring配置文件通过 scope属性指定 Bean的作用域.该属性可以接收 singleton、prototype、request、session和globalSession五个值,分别代表上面的5个作用域。
bean后置处理器
Spring框架提供了很好的扩展性,除了可以与各种第三方框架良好整合外,其loC容器也允许开发者进行扩展,这种扩展甚至无须实现BeanFactory或ApplicationContext接口,而是允许通过两个后处理器对loC容器进行扩展。Spring提供了两种常用的后处理器。
- Bean后处理器:这种处理器会对容器中的Bean进行后处理,对Bean进行额外加强。
- 容器后处理器:这种后处理器对loC容器进行后处理,用于增强容器功能。
bean后处理器
BeanPostProcessor是Bean级处理器,用于在bean实例化后、初始化后自定义修改bean实例,如属性校验、针对自定义bean做统一处理等。
BeanPostProcessor接口中定义了两个方法:
- postProcessBeforelnitialization方法,在任何bean初始化回调「如InitializingBean接口的afterPropertiesSet方法、自定义的初始化方法」之前,使BeanPostProcessor应用于给定的bean实例,其返回值可以是bean本身或其包装类。
- postProcessAfterInitialization方法,在 bean回调初始化方法后调用。
Spring中Bean的实例化过程图示:

@Component
@Data
public class MyBean {
private String myProperty = "";
public void doSomething() {
System.out.println("MyBean.doSomething()执行,myProperty="+myProperty);
}
}
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean , String beanName) throws BeansException {
if (bean instanceof MyBean){
MyBean myBean = (MyBean)bean;
myBean.setMyProperty(myBean.getMyProperty()+"自定义属性-before");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean , String beanName) throws BeansException {
if (bean instanceof MyBean){
MyBean myBean = (MyBean)bean;
myBean.setMyProperty(myBean.getMyProperty()+"自定义属性-after");
}
return bean;
}
}
<bean class="com.origin.d702.MyBeanPostProcessor"/>
注意:
1、接口中的两个方法都要将传入的bean返回,而不能返回null、如果返回的是null那么我们通过getBean方法将得不到目标。
2、BeanFactory和ApplicationContext 对待 bean后置处理器稍有不同。ApplicationContext会自动检测在配置文件中实现了BeanPostProcessor接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。而使用BeanFactory实现的时候,bean后置处理器必须通过代码显式地去注册,在loC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法。
另外,不要将BeanPostProcessor标记为延迟初始化。因为如果这样做,Spring容器将不会注册它们,自定义逻辑也就无法得到应用。假如你在
BeanPostProcessor实际应用分析
- 属性注入:可以通过实现BeanPostProcessor接口,在Bean实例化后、初始化之前,对Bean的属性进行自定义注入。例如,可以在BeanPostProcessor的postProcessBeforelnitialization方法中,对Bean的属性进行修改或赋值,从而实现属性注入的定制化需求。
- AOP预处理:可以通过实现BeanPostProcessor接口,在Bean实例化后、初始化之前,对Bean进行AOP相关的预处理。例如,可以在BeanPostProcessor的postProcessBeforelnitialization方法中,为Bean动态生成代理对象,实现AOP面向切面的功能。
- 定制初始化逻辑:可以通过实现BeanPostProcessor接口,在Bean初始化阶段,对Bean进行自定义的初始化逻辑。例如,可以在BeanPostProcessor的postProcessAfterInitialization方法中,执行一些初始化操作,例如数据初始化、资源加载等。
- 数据校验:可以通过实现BeanPostProcessor接口,在Bean初始化后,对Bean中的数据进行校验。例如,可以在BeanPostProcessor的postProcessAfterInitialization方法中,对 Bean中的数据进行验证,确保数据的合法性和完整性。
- 资源回收:可以通过实现BeanPostProcessor接口,在Bean销毁前,对Bean中的资源进行回收操作。例如,可以在BeanPostProcessor的postProcessBeforeDestruction方法中,执行资源的释放、关闭等操作
容器后置处理器
Spring还提供了一种容器后处理器,容器后处理器负责处理容器本身。容器后处理器必须实现BeanFactoryPostProcessor接口,该接口声明了如下一个方法:
- postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
该方法由Spring容器自动调用,在此方法中可以对Spring容器进行自定义扩展,也可以对Spring容器不做任何处理。
同BeanPostProcessor类似,ApplicationContext可自动检测到容器中的容器后处理器,并且自动注册容器后处理器。但如果使用BeanFactory作为Spring容器、则必须手动调用该容器后处理器来处理BeanFactory容器。
实现了BeanFactoryPostProcessor接口的容器后处理器不仅可以对BeanFactory执行后处理,也可以对ApplicationContext容器执行后处理。容器后处理器还可以用来注册额外的属性编辑器。
Spring提供了如下几个常用的容器后处理器:
- PropertyPlaceholderConfigurer属性占位符配置器。
- PropertyOverrideConfigurer重写占位符配置器。
- CustomAutoWrieConfigurer:自定义自动装配的配置器。
- CustomScopeConfigurer:自定义作用域的配置器。
容器后处理器通常用于对于Spring容器进行处理,并且总是在容器实例化其他Bean之前,读取配置文件的元数据,也可以修改这些元数据。
在Spring的配置文件中可以配置多个容器后处理器,在每个容器后处理器中可使用order属性来控制容器后处理器的执行次序。容器后处理器的作用域范围是容器级,它只能对容器本身进行处理,而不对容器中的Bean 进行处理。
属性占位符配置器
PropertyPlaceholderConfigurer是一个容器后处理器,负责读取属性文件里的属性值,并将这些属性设置成Spring配置文件的数据。例如配置数据库连接,或者配置数据库连接池,只需要将特定的信息,比如连接数据库的URL、用户名、密码等放在特定的属性文件中,当切换数据库时,只需要改属性文件即可,则无需改Spring 文件。
重写占位符配置器
PropertyOverrideConfiqurer是Spring提供的另一个容器后处理器,这个容器后处理器比PropertyPlaceholderConfigurer更加强大PropertyOverrideConfigurer的属性文件指定的信息可以直接覆盖Spring配置文件中的元数据。
举例说明:假如 BeanA中有个属性name,Spring容器为其注入的值为“zhangsan”.PropertyOverrideConfigurer的属性文件中 name 的值为“lisi”,那么属性文件中的 name属性会覆盖掉 Spring 配置文件中注入的值。使用PropertyOverrideConfigurer的属性文件,每条属性应该使用如下格式:beanld.property=value针对于下面的work示例,属性文件中的书写格式为:worker.age=55 岁beanld是属性占位符试图覆盖的Bean的id,property是试图覆盖的属性的属性名。
注解配置bean类
搜索 bean类
既然不再使用Spring配置文件来配置任何Bean实例,那么只能由Spring自动搜索某些路径下的Java类,并将这些Java类注册成 Bean实例。
Spring没有采用“约定优于配置”的策略,Spring依然要求程序员显示指定搜索哪些路径下的Java类,Spring将会把合适的Java类全部注册成Spring Bean。问题是:Spring如何知道应该把哪些Java类当成Bean类处理?
这就需要使用Annotation,Spring通过使用一些特殊的Annotation来标注Bean类。如下所示:
- @Compgnent:标注一个普通的 Spring Bean类。
- @Controller:标注一个控制器组件类。
- @Service:标注一个业务逻辑组件类。
- @Repository:标注一个DAO组件类。
指定了某些类可以作为SpringBean类使用后,最后还需要让Spring搜索这些Bean的路径,此时需要配置
文件中导入context命名空间,并指定一个简单的搜索路径。
<!-自动扫描指定包及其子包下的所有的Bean类-->
<context:component-scan base-package="com.yuand.scanBean"/>
@Component("xiaohei")
@Data
public class Dog {
@Value("小狗狗")
private String dName;
}
指定Bean的作用域
当采用零配置方式来管理Bean实例时,可以使用@ScopeAnnotation来指定Bean实例的作用域。例如如下
Java类代码:
@Scope("prototype")
使用@Resource配置依赖
@Resource 位于javax.annotation包下,是来自于Java E规范下的一个Annotation,Spring直接借鉴了该Annotation,通过使用该 Annotation为目标 Bean指定协作者Bean。
@Resource有一个name属性,在默认情况下,Spring将这个值解释为需要被注入的的Bean实例的id。
pom依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
</dependency>
@Component("xiaohei")
@Data
public class Dog {
@Value("小狗狗")
private String dName;
// @Autowired
@Resource
private Cat cat;
}
使用@PostConstruct和@PreDestroy定制声明周期行为
@PostConstruct 和@PreDestroy 同样位于javax.annotation.包下,也是来自于Java EE规范的两个Annotation.Spring直接借鉴了它们,用于定制Spring容器中Bean的声明周期行为。
前面介绍过 Spring 生命周期时提供了bean元素的两个属性init-method、destory-method,一个是指定Bean初始化后,调用指定的方法增强初始化。一个是指定Spring容器在销毁Bean之前调用的方法,完成一些处理。
@Component
@Data
public class Cat {
@Value("小猫猫")
private String cName;
@PostConstruct
public void init(){
System.out.println("初始化...");
}
@PreDestroy
public void destory(){
System.out.println("销毁...");
}
}
bean生命周期
五步骤版本
- 实例化
- 依赖注入
- 初始化
- 使用Bean
- 销毁Bean
七步骤版本
- 实例化
- 依赖注入
- 初始化前 BeanPostProcessor before方法
- 初始化
- 初始化前 BeanPostProcessor after方法
- 使用Bean
- 销毁Bean
十步骤版本
- 实例化
- 依赖注入
- BeanNameAwareBeanFactoryAare方法执行啦
- 初始化前 BeanPostProcessor before方法
- InitialingBean接口的方法执行啦!
- 初始化
- 初始化前 BeanPostProcessor after方法
- 使用Bean
- DisposableBean接口的方法执行啦!
- 销毁Bean
