连载地址
总览、配置组件 Configure Components
配置组件一、 @Configuration 注解
1.1 功能说明
把一个类作为一个IOC容器,它的某个方法头上如果注册了@Bean
,就会作为这个Spring容器中的Bean。以前我们写在配置文件,配置一个个bean,现在使用这个注解即可。
1.2 要点说明
-
@Bean
默认用方法名作为bean的key,如果要自定义key,可以设置@Bean
的value值。 -
person方法里使用new 对象其实不是真的new出来的,是使用原型模式生成的,所以new几次都是同一实例,只会调用一次,注入拿到的Person都是同一个。
1.3 源码
@Configuration
注解源码:
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
}
@Bean
源码:
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
1.4 demo
MyConfiguration注解配置类:
@Configuration
public class MyConfiguration {
/**
* 1、只会调用一次,注入拿到的Cat都是同一个
* 2、默认用方法名作为bean的key,获取bean时,默认用方法名cat
* @return
*/
@Bean
public Cat cat(){
return new Cat("小花猫",2);
}
/**
* 1、只会调用一次
* 2、自定义bean的key,设置value值为duck
* @return
*/
@Bean("duck")
public Duck duck2(){
return new Duck("唐老鸭",1);
}
}
MyTest测试类:
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConfiguration.class);
System.out.println("默认用方法名取bean---------------");
//默认用方法名取bean
Object bean1 = app.getBean("cat");
Object bean2 = app.getBean("cat");
//注入拿到的Cat都是同一个
Boolean e = bean1 == bean2;
System.out.println(bean1);
System.out.println(bean2);
System.out.println(e);
System.out.println();
System.out.println("用class type取bean---------------");
//用class type取bean
Cat cat = app.getBean(Cat.class);
System.out.println(cat);
System.out.println(bean1==cat);
System.out.println();
System.out.println("用自定义key取bean---------------");
Object duck = app.getBean("duck");
System.out.println(duck);
}
}
运行结果:
默认用方法名取bean---------------
Cat{name='小花猫', age=2}
Cat{name='小花猫', age=2}
true
用class type取bean---------------
Cat{name='小花猫', age=2}
true
1.5 原始xml方式写法
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.ac.annotation.demo.configures.configuration.Cat">
<property name="name" value="小花猫"/>
<property name="age" value="2"/>
</bean>
<bean id="duck" class="com.ac.annotation.demo.configures.configuration.Duck">
<property name="name" value="唐老鸭"/>
<property name="age" value="1"/>
</bean>
</beans>
二、 @ComponentScan
2.1 功能说明
就跟之前xml 中的<context:component-scan>
效果一样,注解在某类上时会扫描项目下的所有组件。
如果你定义了包路径的话就扫描该路径下的所有组件,记住是组件,不是所有类,比如@Controller
、@Service
、@Repository
这种,或者@Component
这种。
总的来说就是扫描一些类,将这些类的实例放到IoC容器中,然后我要用的时候不需要new,使用依赖注入即可。
2.2 要点说明
2.2.1 Filter类型:
public enum FilterType {
ANNOTATION, //按照注解
ASSIGNABLE_TYPE, //扫描指定的类型
ASPECTJ,
REGEX, //使用正则表达式
CUSTOM //自定义过滤规则
}
2.3 源码
@ComponentScan
注解源码:
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.type.filter.TypeFilter;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
boolean useDefaultFilters() default true;
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
2.4 demo
2.4.1 辅助类
1、普通java类PersonVO
package com.ac.annotation.demo.configures.componentscan;
public class PersonVO {
}
2、PersonController类
package com.ac.annotation.demo.configures.componentscan;
import org.springframework.stereotype.Controller;
@Controller
public class PersonController {
}
2.4.2 测试类
1、注解在某类上时会扫描该类所在包下的所有类
@Configuration
@ComponentScan
public class MyComponentScan {
// 注解在某类上时会扫描该类所在包下的所有类
}
2、定义了包路径的话就扫描该路径下的所有组件
@Configuration
@ComponentScan("com.ac.annotation.demo.configures.componentscan")
public class MyComponentScan2 {
// 定义了包路径的话就扫描该路径下的所有组件,记住是组件,不是所有类,比如`@Controller`、`@Service`、`@Repository`这种,或者`@Component`这种。
}
3、只扫描配置了指定注解的类,比如配置了@Controller注解的类
@Configuration
@ComponentScan(
value = "com.ac.annotation.demo.configures.componentscan",
includeFilters={@ComponentScan.Filter(type= FilterType.ANNOTATION,value= Controller.class)},
useDefaultFilters=false)
public class MyComponentScan3 {
// 只扫描配置了指定注解的类,比如配置了@Controller注解的类
}
4、扫描指定的类型
@Configuration
@ComponentScan(
value = "com.ac.annotation.demo.configures.componentscan",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonVO.class, Person.class, Worker.class})}
)
public class MyComponentScan4 {
// 扫描指定的类型
// 注意:PersonVO只是一个普通的java类,没有任何注解,但也能被扫描出来
}
5、自定义过滤规则
MyComponentScan5:
@Configuration
@ComponentScan(
value = "com.ac.annotation.demo.configures.componentscan",
includeFilters={@ComponentScan.Filter(type= FilterType.CUSTOM,value= MyScanFilter.class)},
useDefaultFilters=false)
@Component
public class MyComponentScan5 {
// 自定义过滤规则
}
MyScanFilter:
public class MyScanFilter implements TypeFilter {
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory){
// 获取当前类所有的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前扫描到的类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取到当前类的所有资源
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
if (className.contains("Controller")) {
return true;
}
return false;
}
}
6、排除过滤器
@Configuration
@ComponentScan(
value = "com.ac.annotation.demo.configures.componentscan",
excludeFilters={@ComponentScan.Filter(type= FilterType.ANNOTATION,value= Controller.class)},
useDefaultFilters=false)
public class MyComponentScan6 {
// 排除过滤器,排除指定注解的类,比如配置了@Controller注解的类
}
2.4.3 测试类
MyTest测试类
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan
* myComponentScan2
* myComponentScan3
* myComponentScan4
* myComponentScan5
* myComponentScan6
* personController
* person
* personVO
* worker
*/
}
@Test
public void test2(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan2.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan2
* myComponentScan
* myComponentScan3
* myComponentScan4
* myComponentScan5
* myComponentScan6
* personController
* person
* personVO
* worker
*/
/**
* 说明:按理说personVO是不会被扫描出来的,这运行结果里却有personVO,
* 是因为MyComponentScan4里把personVO扫描出来了,而MyComponentScan2又扫描了MyComponentScan4,所以personVO就出来了。
* 如果MyComponentScan4注释掉,personVO就不会出来了。
*/
}
@Test
public void test3(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan3.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan3
* personController
*/
}
@Test
public void test4(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan4.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan4
* personVO
* person
* worker
*/
}
@Test
public void test5(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan5.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan5
* personController
*/
}
@Test
public void test6(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyComponentScan6.class);
printBeanNames(app);
/**
* 运行结果:
* myComponentScan6
*/
}
private void printBeanNames(ApplicationContext app){
String[] beanNames = app.getBeanDefinitionNames();
for(String beanName : beanNames){
if(!beanName.contains("springframework")){
System.out.println(beanName);
}
}
}
}
2.5 原始xml方式写法
<context:component-scan base-package="com.ac.annotation"/>
三、@Scope 注解
3.1 功能说明
该注解用于指定作用域,用在类上。
3.2 要点说明
Scope有四种范围:
- singleton:单例,默认scope
- prototype:原型,多例,每次都会是新的一个对象
- request:主要用于web模块,同一次请求值创建一个实例
- session:主要用于web模块, 同一个session只创建一个实例
3.3 源码
@Scope
注解源码
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
3.4 demo
MyScope 注解配置类:
@Configuration
public class MyScope {
@Scope("singleton")
@Bean
public Boss singletonBoss() {
return new Boss("AlanChen", 18);
}
@Scope("prototype")
@Bean
public Boss prototypeBoss() {
return new Boss("AC", 30);
}
}
MyTest测试类:
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyScope.class);
System.out.println("singleton测试---------------");
Object bean1 = app.getBean("singletonBoss");
Object bean2 = app.getBean("singletonBoss");
System.out.println(bean1 == bean2);
System.out.println("prototype测试---------------");
Object bean3 = app.getBean("prototypeBoss");
Object bean4 = app.getBean("prototypeBoss");
System.out.println(bean3 == bean4);
}
}
运行结果:
singleton测试---------------
true
prototype测试---------------
false
四、@Lazy 注解
4.1 功能说明
延时初始化
4.2 要点说明
- 默认不延时加载,如果加上此注解则使当前类延时加载。
- 延时加载只针对单例Bean(即@Scope为singleton的Bean)起作用。
- 加上此注解后容器启动时不创建对象,调用对象的功能时才创建对象。
4.3 源码
@Lazy
注解源码
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
boolean value() default true;
}
4.4 demo
MyLazy 注解配置类:
@Configuration
public class MyLazy {
@Bean
public Dog normalDog() {
System.out.println("将normalDog添加到IOC容器中");
return new Dog("灰灰", 1);
}
@Lazy
@Bean
public Dog lazyDog() {
//延迟加载,调用此对象时才会去创建
System.out.println("将lazyDog添加到IOC容器中");
return new Dog("毛毛", 2);
}
}
MyTest测试类:
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyLazy.class);
System.out.println("IOC容器已创建---------------");
Object bean1 = app.getBean("normalDog");
Object bean2 = app.getBean("lazyDog");
System.out.println(bean1 == bean2);
}
}
运行结果:
将normalDog添加到IOC容器中
IOC容器已创建---------------
将lazyDog添加到IOC容器中
false
五、@Conditional 注解
5.1 功能说明
Spring4开始提供,作用是按照一定的条件进行判断,如果满足条件则给容器注册Bean。
5.2 要点说明
使用@Conditional注解要配合Condition类
5.3 源码
@Conditional
注解源码
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
Condition接口源码
package org.springframework.context.annotation;
import org.springframework.core.type.AnnotatedTypeMetadata;
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext var1, AnnotatedTypeMetadata var2);
}
5.4 demo
5.4.1 驱动condition
1、WindowsCondition
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println("WindowsCondition,当前系统环境为:"+osName);
if (osName.contains("Windows")) {
return true;
}
return false;
}
}
2、LinuxCondition
public class LinuxCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String osName = environment.getProperty("os.name");
System.out.println("LinuxCondition,当前系统环境为:"+osName);
if (osName.contains("Linux")) {
return true;
}
return false;
}
}
5.4.2 MyConditional
@Configuration
public class MyConditional {
@Conditional(WindowsCondition.class)
@Bean("printDrive")
public PrintDrive windowsDrive(){
System.out.println("创建windows打印驱动");
return new PrintDrive("windows","windows打印驱动");
}
@Conditional(LinuxCondition.class)
@Bean("printDrive")
public PrintDrive linuxDrive(){
System.out.println("创建linux打印驱动");
return new PrintDrive("linux","linux打印驱动");
}
}
5.4.3 PrintDrive
public class PrintDrive {
private String os;
private String name;
public PrintDrive() {
}
public PrintDrive(String os, String name) {
this.os = os;
this.name = name;
}
public String getOs() {
return os;
}
public void setOs(String os) {
this.os = os;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "PrintDrive{" +
"os='" + os + '\'' +
", name='" + name + '\'' +
'}';
}
}
5.4.4 MyTest
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyConditional.class);
System.out.println("IOC容器已创建---------------");
PrintDrive drive = app.getBean(PrintDrive.class);
System.out.println(drive);
}
}
运行结果:
WindowsCondition,当前系统环境为:Linux
LinuxCondition,当前系统环境为:Linux
创建linux打印驱动
IOC容器已创建---------------
PrintDrive{os='linux', name='linux打印驱动'}
5.5 配置VM参数
运行测试前,配置VM参数:
-ea -Dos.name=Linux
配置VM参数
六、@Import 注解
6.1 功能说明
导入外部资源,相当于手动指定第三方资源,把其实例加载到IOC容器中。
6.2 要点说明
-
导入的类必须存在无参的构造方法
-
@Import
导入的组件命名是类的全限定名 -
通过
@Bean
导入的就是方法名
6.3 @Import
导入的三种类型
1、导入类
- A、导入普通类(4.2版本之后)
- B、导入带有@Configuration的配置类(4.2 版本之前只可以导入配置类)
2、ImportSelector的实现。
3、ImportBeanDefinitionRegistrar的实现。
6.4 源码
@Import
注解源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
6.5 demo
6.5.1 导入普通类
1、新建一个普通的java类:UserEntity
/**
* 注意:这是一个普通Java类,没有任何注解
* @author AlanChen
*/
public class UserEntity {
public void run(String str) {
System.out.println(str);
}
public void printName() {
System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());
}
}
注意:UserEntity是一个普通Java类,没有任何注解。
2、新建一个MyImport,在类上面加上@Configuration
,加上@Configuration
是为了能让Spring扫描到这个类,并且直接通过@Import
引入UserEntity类。
@Import({UserEntity.class})
@Configuration
public class MyImport {
}
3、测试
UserEntity是一个普通的类,现在可以通过ApplicationContext获取到然后后调用,就直接说明已经被Spring注入并管理了。
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserEntity bean = app.getBean(UserEntity.class);
bean.printName();
bean.run("run userEntity");
}
运行结果:
类名 :com.ac.annotation.demo.configures.import2.UserEntity
run userEntity
6.5.2 导入带有@Configuration
的配置类
1、新建导入带有@Configuration
的配置类:UserConfig
@Configuration
public class UserConfig {
public void run(String str) {
System.out.println(str);
}
public void printName() {
System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());
}
}
2、在MyImport.class
里面直接引入UserConfig
@Import({UserEntity.class,UserConfig.class})
@Configuration
public class MyImport {
}
3、测试
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserEntity bean = app.getBean(UserEntity.class);
bean.printName();
bean.run("run userEntity");
}
@Test
public void test2(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserConfig bean = app.getBean(UserConfig.class);
bean.printName();
bean.run("run UserConfig");
}
}
执行test2方法,运行结果:
类名 :com.ac.annotation.demo.configures.import2.UserConfig
run UserConfig
6.5.3 通过ImportSelector
方式导入类
1、新建UserComponent类
public class UserComponent {
public void run(String str) {
System.out.println(str);
}
public void printName() {
System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());
}
}
2、新建MyImportSelector.class
实现ImportSelector
接口,注入UserComponent.class
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.ac.annotation.demo.configures.import2.UserComponent"};
}
}
3、MyImport
上面引入MyImportSelector.class
@Import({UserEntity.class,UserConfig.class,MyImportSelector.class})
@Configuration
public class MyImport {
}
4、测试
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserEntity bean = app.getBean(UserEntity.class);
bean.printName();
bean.run("run userEntity");
}
@Test
public void test2(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserConfig bean = app.getBean(UserConfig.class);
bean.printName();
bean.run("run UserConfig");
}
@Test
public void test3(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserComponent bean = app.getBean(UserComponent.class);
bean.printName();
bean.run("run UserComponent");
}
}
执行test3方法,运行结果:
类名 :com.ac.annotation.demo.configures.import2.UserComponent
run UserComponent
6.5.4 通过ImportBeanDefinitionRegistrar方式导入类
1、新建类UserDao
public class UserDao {
public void run(String str) {
System.out.println(str);
}
public void printName() {
System.out.println("类名 :" + Thread.currentThread().getStackTrace()[1].getClassName());
}
}
2、新建MyImportBeanDefinitionRegistrar.class
,实现接口ImportBeanDefinitionRegistrar
,注入UserDao.class
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean hadEntity = registry.containsBeanDefinition("com.ac.annotation.demo.configures.import2.UserEntity");
System.out.println("hadEntity=" + hadEntity);
//假装加了一段逻辑,当然也可以直接注入UserDao
if (hadEntity) {
RootBeanDefinition root = new RootBeanDefinition(UserDao.class);
registry.registerBeanDefinition("userDao", root);
}
}
}
3、MyImport类上加上导入MyImportBeanDefinitionRegistrar.class
@Import({UserEntity.class,UserConfig.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
@Configuration
public class MyImport {
}
4、测试
public class MyTest {
@Test
public void test(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserEntity bean = app.getBean(UserEntity.class);
bean.printName();
bean.run("run userEntity");
}
@Test
public void test2(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserConfig bean = app.getBean(UserConfig.class);
bean.printName();
bean.run("run UserConfig");
}
@Test
public void test3(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserComponent bean = app.getBean(UserComponent.class);
bean.printName();
bean.run("run UserComponent");
}
@Test
public void test4(){
ApplicationContext app = new AnnotationConfigApplicationContext(MyImport.class);
UserDao bean = app.getBean(UserDao.class);
bean.printName();
bean.run("run UserDao");
}
}
执行test4方法,运行结果:
hadEntity=true
类名 :com.ac.annotation.demo.configures.import2.UserDao
run UserDao
七、生命周期控制
生命周期控制有四种实现方式,分别是:
1、方式一
使用@Bean注解的生命周期参数
@Bean(initMethod = "start",destroyMethod = "stop")
2、方式二
实现接口InitializingBean, DisposableBean
3、方式三
在方法上使用生命周期注解:
-
@PostConstruct
用于指定初始化方法(用在方法上) -
@PreDestroy
用于指定销毁方法(用在方法上) -
@DependsOn
定义Bean初始化和销毁的顺序
4、 方式四
实现接口BeanPostProcessor
7.1 方式一:使用@Bean注解的生命周期参数
7.1.1 代码
public class BaoMaCar {
public void start() {
System.out.println("宝马汽车启动......");
}
public void run() {
System.out.println("宝马汽车行驶中......");
}
public void stop() {
System.out.println("宝马汽车熄火......");
}
}
@Configuration
public class LifeOneConfig {
@Bean(initMethod = "start",destroyMethod = "stop")
public BaoMaCar baoMaCar(){
return new BaoMaCar();
}
}
public class MyTest {
@Test
public void test(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifeOneConfig.class);
BaoMaCar bean = app.getBean(BaoMaCar.class);
bean.run();
//关闭content,会调用bean的destroyMethod
app.close();
}
}
7.1.2 运行结果
宝马汽车启动......
宝马汽车行驶中......
九月 08, 2022 6:27:55 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ecf72fd: startup date [Thu Sep 08 18:27:55 CST 2022]; root of context hierarchy
宝马汽车熄火......
7.2 方式二:实现接口InitializingBean, DisposableBean
7.2.1 代码
public class BenChiCar implements InitializingBean, DisposableBean {
/**
* 重写接口方法
*/
public void destroy() {
stop();
}
/**
* 重写接口方法
*/
public void afterPropertiesSet() {
start();
}
public void start() {
System.out.println("奔驰汽车启动......");
}
public void run() {
System.out.println("奔驰汽车行驶中......");
}
public void stop() {
System.out.println("奔驰汽车熄火......");
}
}
@Configuration
public class LifeTwoConfig {
@Bean
public BenChiCar benChiCar(){
return new BenChiCar();
}
}
public class MyTest {
@Test
public void test(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifeTwoConfig.class);
BenChiCar bean = app.getBean(BenChiCar.class);
bean.run();
//关闭content,会调用bean的destroyMethod
app.close();
}
}
7.2.2 运行结果
奔驰汽车启动......
奔驰汽车行驶中......
九月 08, 2022 6:30:25 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ecf72fd: startup date [Thu Sep 08 18:30:25 CST 2022]; root of context hierarchy
奔驰汽车熄火......
7.3 方式三:在方法上使用生命周期注解
7.3.1 代码
public class AoDiCar {
@PostConstruct
public void start() {
System.out.println("奥迪汽车启动......");
}
public void run() {
System.out.println("奥迪汽车行驶中......");
}
@PreDestroy
public void stop() {
System.out.println("奥迪汽车熄火......");
}
}
@Configuration
public class LifeThreeConfig {
@Bean
public AoDiCar aoDiCar(){
return new AoDiCar();
}
}
public class MyTest {
@Test
public void test(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifeThreeConfig.class);
AoDiCar bean = app.getBean(AoDiCar.class);
bean.run();
//关闭content,会调用bean的destroyMethod
app.close();
}
}
7.3.2 运行结果
奥迪汽车启动......
奥迪汽车行驶中......
九月 08, 2022 6:32:01 下午 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@3ecf72fd: startup date [Thu Sep 08 18:32:01 CST 2022]; root of context hierarchy
奥迪汽车熄火......
7.4 方式四:实现接口BeanPostProcessor
这种方式最灵活,这样写定义类,可以在其中获取所有bean,可以针对性的处理
7.4.1 代码
*/
public class FuTeCar{
public void start() {
System.out.println("福特汽车启动......");
}
public void run() {
System.out.println("福特汽车行驶中......");
}
public void stop() {
System.out.println("福特汽车熄火......");
}
}
@Configuration
@ComponentScan
public class LifeFourConfig {
@Bean
public FuTeCar fuTeCar() {
return new FuTeCar();
}
}
@Configuration
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* 重写接口
*/
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println(beanName);
if (bean instanceof FuTeCar) {
FuTeCar fuTeCar = (FuTeCar) bean;
fuTeCar.start();
}
return bean;
}
/**
* 重写接口
*/
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof FuTeCar) {
FuTeCar fuTeCar = (FuTeCar) bean;
fuTeCar.run();
}
return bean;
}
}
public class MyTest {
@Test
public void test() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(LifeFourConfig.class);
System.out.println("IOC容器创建完成");
//关闭content,会调用bean的destroyMethod
app.close();
}
}
7.4.2 运行结果
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
lifeFourConfig
fuTeCar
福特汽车启动......
福特汽车行驶中......
IOC容器创建完成
网友评论