spring

[2]Spring 5 注解编程基础组件-配置类注解

2022-09-09  本文已影响0人  AC编程

连载地址

总览、配置组件 Configure Components

配置组件

一、 @Configuration 注解

1.1 功能说明

把一个类作为一个IOC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。以前我们写在配置文件,配置一个个bean,现在使用这个注解即可。

1.2 要点说明
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有四种范围:

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 要点说明
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 要点说明
6.3 @Import导入的三种类型

1、导入类

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、方式三
在方法上使用生命周期注解:

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容器创建完成
上一篇 下一篇

猜你喜欢

热点阅读