美文网首页
Spring注解驱动开发

Spring注解驱动开发

作者: WongSilver | 来源:发表于2020-07-19 18:34 被阅读0次

注解:

注解 释义
@Configuration 告诉Spring这是一个配置类
@Bean 注册一个Bean,类型是返回值类型,默认方法名作为ID
@Component 告诉容器这是个组件(泛指各种组件)
@ComponentScan 包扫描(为了实例化对象)
@Filter 过滤@ComponentScan中不想扫描的组件[1.1]
@Repository 标注数据访问组件,即DAO组件
@Service 标注业务层组件
@Controller 用于标注控制层组件(如struts中的action)
@Scope 实例化的模式[1.2]
@Lazy 容器启动不创建对象,第一次使用时创建
@Conditional 按照一定条件判断满足条件给容器中注册bean[1.3]
@Import 快速给容器中导入一个组件[1.4]
@PostConstruct 标注这个方法为初始化方法,对象创建并赋值后调用[3.3]
@PreDestroy 标注这个方法为销毁方法,容器移除对象之前调用[3.3]



组件注册:

  1. 包扫描+组件标注注解 (@Controller/@Service/@Repository/@Component) [自己写的类]
  2. @Bean (例如:实例化一个对象返回) [导入的第三方包的组件]
  3. @Impoer [快速给容器中导入一个组件]
  4. 使用Spring提供的FactoryBean(工厂Bean)[2.1]



生命周期:

  1. 通过@Bean注解指定初始化和销毁方法:指定init-method和destory-method[3.1]
  2. 通过让bean实现InitializingBean接口定义初始化逻辑,实现DisposableBean接口定义销毁逻辑[3.2]
  3. 可以使用JSR-250里的@PostConstruct和@PreDestroy注解标注初始化和销毁方法[3.3]
  4. BeanPostProcessor:bean的后置处理器,在bean初始化前后进行一些处理工作,以及其他应用[3.4]

构造(对象创建)

  • 单实例:在容器创建时创建对象
  • 多实例:在每次获取时创建对象

初始化前调用:

  • BeanPostProcessor.postProcessBeforeInitialization

初始化:

  • 对象创建完成,并赋值好,调用初始化方法...

初始化后调用:

  • BeanPostProcessor.postProcessAfterInitialization

销毁:

  • 单实例:容器关闭时销毁
  • 多实例:容器管理这个bean,容器不会调用销毁方法



脚注:

[1.1]
// 在配置类前加@ComponentScan
// 参数一:value:指定扫描的包
// 参数二:excludeFilters/includeFilters = Filter[],扫描的时按照规则排除哪些组件/扫描时只需要包含哪些组件
// 参数三:useDefaultFilters,默认扫描规则扫描所有,使用includeFilters时要禁用默认规则

// @Filter
// FilterType.ANNOTATION(),按照注解
// FilterType.ASSIGNABLE_TYPE, 按照给定的类型
// FilterType.ASPECTJ,使用ASPECTJ表达式
// FilterType.REGEX,使用正则表达式
// FilterType.CUSTOM,使用自定义规则
@ComponentScan(value = "edu.wong", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = { Controller.class }),
        @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { BookService.class }),
        @Filter(type = FilterType.CUSTOM, classes = { MyTypeFilter.class }) }, useDefaultFilters = false)
        

// 自定义扫描规则实例(必须实现TypeFilter)
public class MyTypeFilter implements TypeFilter {

    /**
     * metadataReader:读取到的当前正在扫描的类的信息
     * metadataReaderFactory:可以获取到其他任何类的信息
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        // 获取当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        // 获取当前正在扫描的类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        // 获取当前资源(类的路径)
        Resource resource = metadataReader.getResource();

        // 获取正在扫描的类名
        String className = classMetadata.getClassName();
        // 包含er的可以被获取
        if (className.contains("er")) {
            return true;
        }
        return false;
    }

}
[1.2]
@Configuration
public class MainConfig {
    /**
     * @Scope
     * singleton:单例模式(默认值),全局有且仅有一个实例,ioc容器启动时会调用方法创建对象放到ioc容器中,以后每次直接从容器中获取
     * prototype:原型模式,ioc容器启动时不会调用方法创建对象,每次获取Bean的时候会有一个新的实例
     * request:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
     * session:每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
     * 
     * @Lazy
     * 懒加载:单例模式下起作用,默认在容器启动时创建对象,容器启动不创建对象.第一次使用使用(获取)Bean创建对象
     */
    @Lazy
    @Scope("singleton")
    @Bean("person")
    public Person person() {
        return new Person("王五", 20);
    }
}
[1.3]
// 标记在类上
// 满足条件,类中的配置的所有bean注册才会生效
@Conditional({ WindownsCondition.class })
@Configuration
public class MainConfig {

    @Lazy
    @Bean("person")
    public Person person() {
        return new Person("王五", 20);
    }

// 标记在方法上
// 使用Conditiona,满足条件,bean注册才会生效
    @Conditional({ WindownsCondition.class })
    @Bean("win")
    public Person person01() {
        return new Person("win", 21);

    }

    @Conditional({ LinuxCondition.class })
    @Bean("linux")
    public Person person02() {
        return new Person("Linux", 22);
    }
}


// 实现Condition接口
public class LinuxCondition implements Condition {
    /**
     * ConditionContext:判断条件能使用的上下文(环境)
     *  AnnotatedTypeMetadata:注释信息
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        // 获取到ioc使用的beanfactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        // 获取当前环境信息
        Environment environment = context.getEnvironment();
        // 获取到bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();

        // 判断容器中注册情况,也可以在容器中注册bean
        boolean containsBeanDefinition = registry.containsBeanDefinition("person");
        String property = environment.getProperty("os.name");
        if (property.contains("Linux")) {
            return true;
        }
        return false;
    }
}
[1.4]
@Configuration

// 在配置文件上直接用 @Import(要导入的组件),id默认是组件的全类名
// 1. 导入单个,导入多个用数组形式
// 2. 可以自定义导入组需要实现件ImportSelector接口后在@import注解中添加
// 3. 可以实现ImportBeanDefinitionRegistrar接口手动注册bean,之后在@import注解中添加
// 如下:
@Import(Color.class)
@Import( {Blue.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class} )
public class MainConfig {
    // TODO
}


// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {

    // 返回值:要导入组件的全类名
    // AnnotationMetadata当前标注@Import类的所有注解信息
    // 方法返回 null 会报空指针异常
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] { "edu.wong.bean.Blue", "edu.wong.bean.Yellow" };
    }
}

// 自定义通过registerBeanDefinition()方法注册bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * AnnotationMetadata 当前类的注解信息
     * BeanDefinitionRegistry BeanDefinitio注册类
     * 把所有需要添加到容器中的bean:调用BeanDefinitionRegistry.registerBeanDefinition手动注册进来
     */
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        // 测试条件如果两种颜色存在就注册TwoColor类
        boolean blue = registry.containsBeanDefinition("edu.wong.bean.Blue");
        boolean yellow = registry.containsBeanDefinition("edu.wong.bean.Yellow");
        if (blue && yellow) {
            // 把TwoColor转换成Bean的定义信息(可以被参数二接收的参数)
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TwoColor.class);
            //  参数一:指定bean名
            //  参数二:指定bean的定义信息
            registry.registerBeanDefinition("twoColor", rootBeanDefinition);
        }
    }
}
[2.1]
//创建一个Spring定义的工场Bean
// FactoryBean<T> T:指定要创建对象的类型
public class MyFactoryBean implements FactoryBean<Color> {

    // 返回一个Color对象这个对象会添加到容器中
    public Color getObject() throws Exception {
        System.out.println("MyFactoryBean......getObject.......");
        return new Color();
    }

    // 返回对象的类型
    // 默认获取的是工厂bean调用getObject创建的对象
    // 要获取工程bean本身需要在id前加上 & 符号
    public Class<?> getObjectType() {
        return Color.class;
    }

    // 是否是单实例
    // true这个Bean在容器中保存一份
    // false每次获取都会创建一个新的
    public boolean isSingleton() {
        return true;
    }
}

// 在配置类里使用@Import()把MyFactoryBean导入到容器
@Import(MyFactoryBean.class)

// 用全类名获取到Bean
// 打印测试 
// 结果:--------->class edu.wong.bean.Color是MyFactoryBean里new的Color

/**
* 在getBean()加'&'如"&edu.wong.bean.MyFactoryBean";可以获取到MyFactoryBean本身,而不是返回值的Bean
*/
Object bean = annotationConfigApplicationContext.getBean("edu.wong.bean.MyFactoryBean");
System.out.println("--------->" + bean.getClass());
[3.1]
public class Car {
    public Car() {
        System.out.println("car constructor...");
    }
    public void init() {
        System.out.println("car...init...");
    }
    public void destory() {
        System.out.println("car...destory...");
    }
}

/**
 * bean的生命周期:创建-->初始化-->销毁
 * 容器管理bean的生命周期:可以自定义初始化和销毁方法,容器bean进行到当前生命周期的时候会调用我们自定义的初始化和销毁方法
 * 
 */
@Configuration
public class MainConfigLifeCycle {

// initMethod指定bean的初始化方法
// destroyMethod指定bean的销毁方法
    @Bean(initMethod = "init", destroyMethod = "destory")
    public Car car() {
        return new Car();
    }
}

// 结果打印:
// car constructor...
// car...init...
// car...destory...
public class IocTestLiftCycle {
    @Test
    public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigLifeCycle.class);
        context.close();
    }

}
[3.2]
// 告诉容器这是个组件
// 实现InitializingBean, DisposableBean两个接口
@Component
public class Car implements InitializingBean, DisposableBean {
    public Car() {
        System.out.println("car constructor...");
    }
    public void destroy() throws Exception {
        System.out.println("car destroy...");
    }
    public void afterPropertiesSet() throws Exception {
        System.out.println("car afterPropertiesSet...");
    }
}

// 扫描edu.wong.bean下的组件
@ComponentScan("edu.wong.bean")
@Configuration
public class MainConfigLifeCycle {
}


// 结果打印:
// car constructor...
// car afterPropertiesSet...
// car destroy...
public class IocTestLiftCycle {
    @Test
    public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigLifeCycle.class);
        context.close();
    }
}
[3.3]
<!-- 找不到这两个注解请在pom.xml下面的添加库 -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>
@Component
public class Car {
    public Car() {
        System.out.println("car constructor......");
    }
// 标注这个方法为初始化方法,对象创建并赋值后调用
    @PostConstruct
    public void init() {
        System.out.println("car init......");
    }
// 标注这个方法为销毁方法,容器移除对象之前调用
    @PreDestroy
    public void destroy() {
        System.out.println("car destroy......");
    }
}
[3.4]
/**
*   @Component:把这个组件加入到容器中
*  会在所有bean初始化之前调用postProcessBeforeInitialization
*  会在所有bean初始化之后调用postProcessAfterInitialization
*  
*  参数一(bean):容器创建好的实例
*  参数二(beanName):这个实例在容器中的名字
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--->postProcessBeforeInitialization---" + beanName + "===>" + bean);
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("--->postProcessAfterInitialization---" + beanName + "===>" + bean);
        return bean;
    }
}


// BeanPostProcessor原理:
// postProcessBeforeInitialization函数的调用链如下:
-->refresh()
-->finishBeanFactoryInitialization(beanFactory)
-->beanFactory.preInstantiateSingletons();
-->getBean(beanName)
-->doGetBean(name, null, null, false);
-->getSingleton(String beanName, ObjectFactory<?> singletonFactory)
-->singletonFactory.getObject()
-->AbstractBeanFactory.this.createBean(beanName, mbd, args)
-->doCreateBean(beanName, mbdToUse, args)
-->initializeBean(beanName, exposedObject, mbd)


// 1.在initializeBean()执行之前,首先执行的是populateBean()函数,该函数主要是为Bean的各个属性赋值。
    try {
            populateBean(beanName, mbd, instanceWrapper);
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }

// 2.在initializeBean(beanName, exposedObject, mbd) 中观察调用的代码
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null),
                beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

// 3.查看applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization函数代码
// 获取容器中的所有BeanPostProcessors,循环调用postProcessBeforeInitialization方法(MyBeanPostProcessor里的方法)
// 一但返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessorsBeforeInitialization
// 对于容器中每一个Bean实例,只要符合if语句条件,都会执行这两个函数,并不是实现BeanPostProcessor接口才会进入这两个函数。
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessAfterInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }

/**
*  BeanPostProcessor流程:
*  populateBean(beanName, mbd, instanceWrapper);
*  initializeBean{
*      applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
*      invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
*      applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
*  }
*/

// ApplicationContextAware示例
@Component
public class Car implements ApplicationContextAware {

    // 把获取到的ioc容器里的内容保存下来
    ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;=
    }
}

// Spring底层对BeanPostProcessor的使用:bean赋值,注入其他组件,@AutoWired,生命周期注解,AsyncAnnotationBeanPostProcessor,......
// ApplicationContextAwareProcessor:实现容器中bean在初始化时,需要得到Spring容器内容
// BeanValidationPostProcessor:一般用于Web数据校验

相关文章

网友评论

      本文标题:Spring注解驱动开发

      本文链接:https://www.haomeiwen.com/subject/rfsrkktx.html