• (2)spring源码解析之前置知识点


    本文是作者原创,版权归作者所有.若要转载,请注明出处.

    最近在看spring源码,但是spring的体系太庞大了,在这里记录一下阅读源码中遇到知识点

    @PostConstruct

    被注解的方法,在对象加载完依赖注入后执行

    看个demo

    package com.day01.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("com.day01")
    public class SpringConfig {
    
    }

    IndexDao

    package com.day01.service;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class IndexDao {
    
        public IndexDao(){
            System.out.println("IndexDao  构造方法");
        }
    }

    IndexService

    @Service
    public class IndexService {
        @Autowired
        private IndexDao indexDao;
    
    
        public IndexService(){
            System.out.println("IndexService  构造方法");
        }
    
        @PostConstruct
        public void init(){
            System.out.println("IndexService  init方法");
        }
    
    
        public void hello(){
            System.out.println("IndexService");
        }
    
    }

    Testday01

    public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
            IndexService indexService = (IndexService) applicationContext.getBean("indexService");
            indexService.hello();
        }

    看结果

     可以看出在spring项目中,在一个bean的初始化过程中,方法执行先后顺序为Constructor > @Autowired > @PostConstruct

    BeanPostProcessor

    BeanPostProcessor是Spring框架的提供的一个扩展点,通过实现BeanPostProcessor接口,程序员就可插手bean实例化的过程

    看demo

    @Component
    public class TestBeanPostProcessor implements BeanPostProcessor {
    
        /**
         * 在bean初始化之前执行
         */
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessBeforeInitialization");
            }
            //这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
            return bean;
        }
    
        /**
         * 初始化之后
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessAfterInitialization");
            }
            return bean;
        }
    
    }

    运行上文的Testday01,看下结果

     可以看出

    ===Spring IOC容器实例化Bean===
    ===调用BeanPostProcessor的postProcessBeforeInitialization方法===
    ===调用bean实例的初始化方法===
    ===调用BeanPostProcessor的postProcessAfterInitialization方法===

    值得说明的是这个接口可以设置多个,会形成一个列表,那么如何确定他们的执行顺序呢?

    Ordered和PriorityOrdered

    Spring提供了Ordered和PriorityOrdered接口,来处理相同接口实现类的优先级问题

    看个demo

    TestBeanPostProcessor

    @Component
    public class TestBeanPostProcessor implements BeanPostProcessor , PriorityOrdered {
    
        /**
         * 在bean初始化之前执行
         */
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessBeforeInitialization");
            }
            //这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
            return bean;
        }
    
        /**
         * 在bean初始化之前执行
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessAfterInitialization");
            }
            return bean;
        }
    
        @Override
        public int getOrder() {
            return 100;//注意这里
        }
    }

    TestBeanPostProcessor2

    @Component
    public class TestBeanPostProcessor2 implements BeanPostProcessor , PriorityOrdered {
    
        /**
         * 在bean初始化之前执行
         */
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessBeforeInitialization2");
            }
            //这里也可以产生代理对象 Proxy.newProxyInstance(),也是aop实现的原理
            return bean;
        }
    
        /**
         * 在bean初始化之前执行
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("indexService")){
                System.out.println("indexService  postProcessAfterInitialization2");
            }
            return bean;
        }
    
        @Override
        public int getOrder() {
            return 99;
        }
    }

    运行test类,看结果

    这段代码的逻辑:

      1. 若对象o1是Ordered接口类型,o2是PriorityOrdered接口类型,那么o2的优先级高于o1

      2. 若对象o1是PriorityOrdered接口类型,o2是Ordered接口类型,那么o1的优先级高于o2

      3. 其他情况,若两者都是Ordered接口类型或两者都是PriorityOrdered接口类型,调用Ordered接口的getOrder方法得到order值,order值越大,优先级越小

    若2个对象中有一个对象实现了PriorityOrdered接口,那么这个对象的优先级更高。

    若2个对象都是PriorityOrdered或Ordered接口的实现类,那么比较Ordered接口的getOrder方法得到order值,值越低,优先级越高

    BeanFactoryPostProcessor

    spring的扩展点之一:实现该接口,可以在spring的bean创建之前修改beandefinitions属性。

    例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改掉。
    可以同时配置多个BeanFactoryPostProcessor,并通过设置'order'属性来控制各个BeanFactoryPostProcessor的执行次序

    看个demo

    @Component
    public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("===============TestBeanFactoryPostProcessor============");
            
        }
    }

    测试类

    public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
            //AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
            IndexService indexService = (IndexService) applicationContext.getBean("indexService");
            indexService.hello();
            IndexService indexService2 = (IndexService) applicationContext.getBean("indexService");
            System.out.println(indexService);
            System.out.println(indexService2);
        }

    运行一下,看结果

     可以看到,spring管理的bean默认是单例的,我们把indexService改成prototype试一下

    @Component
    public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("===============TestBeanFactoryPostProcessor============");
            BeanDefinition indexService = beanFactory.getBeanDefinition("indexService");
            String scope = indexService.getScope();
            System.out.println(scope);//singleton
            //indexService.setScope("singleton");
            indexService.setScope("prototype");//设置为原型
            System.out.println(scope);//singleton
        }
    }

    看下结果

    BeanDefinitionRegistryPostProcessor

    BeanDefinitionRegistryPostProcessor继承了BeanFactoryPostProcessor接口,并可以注册bean到spring容器中,一共要实现以下两个方法:

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException:
    该方法的实现中,主要用来对bean定义做一些改变。
    
    void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException:
    该方法用来注册更多的bean到spring容器中,详细观察入参BeanDefinitionRegistry接口,看看这个参数能带给我们什么能力。

    看个demo

    public class IndexService2  {
    
        private ApplicationContext applicationContext;
        public IndexService2(){
            System.out.println("IndexService2  构造方法");
        }
    
        @PostConstruct
        public void init(){
            System.out.println("IndexService2  init方法");
        }
    
    
        public void hello(){
            System.out.println("IndexService2 hello");
        }
        
    }

    注意:IndexService2并没有@Component注解,说明这个类并没有交给spring管理,继续

    @Component
    public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
            GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
            genericBeanDefinition.setScope("singleton");
            genericBeanDefinition.setBeanClass(IndexService2.class);//将IndexService2交给spring管理
            registry.registerBeanDefinition("indexService2",genericBeanDefinition);
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("===============MyBeanDefinitionRegistryPostProcessor============");
        }
    }

    注意上述代码中通过BeanDefinitionRegistryPostProcessor 将IndexService2手动注册交给spring管理

    运行test类

    public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
            //AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
            IndexService indexService = (IndexService) applicationContext.getBean("indexService");
            indexService.hello();
            IndexService2 indexService2 = (IndexService2) applicationContext.getBean("indexService2");
            System.out.println(indexService);
            System.out.println(indexService2);
        }

    看结果

    ApplicationContextAware

    我们可以通过注解@Autowired 很简单方便获取bean,虽然这种方法很简单方便,但是有些特殊场景用不了,比如静态方法中不能使用

     此时可以借助ApplicationContextAware获取bean

    看个demo

    @Service
    public class TestServiceImpl {
    
        public String hello(){
            return "hello world";
        }
    
    }

    这里无法注入TestServiceImpl 无法使用,看demo

    @Component
    public class ApplicationContextUtil implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext = null;
        @Autowired
        private TestServiceImpl testService;
    
        /**
         * 实现ApplicationContextAware接口, 注入Context到静态变量中.
         */
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            ApplicationContextUtil.applicationContext = applicationContext;
        }
    
        /**
         * 获取静态变量中的ApplicationContext.
         */
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        /**
         * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
         */
        @SuppressWarnings("unchecked")
        public static <T> T getBean(String name) {
            return (T) applicationContext.getBean(name);
        }
    
        /**
         * 从静态变量applicationContext中得到Bean, 自动转型为所赋值对象的类型.
         */
        public static <T> T getBean(Class<T> requiredType) {
            return applicationContext.getBean(requiredType);
        }
    
        /*public static String test(){
            String hello = testService.hello();
        }*/
    }

    看测试类

    public static void main(String[] args) {
            AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
            //AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(IndexService.class);
            IndexService indexService = (IndexService) applicationContext.getBean("indexService");
            indexService.hello();
            System.out.println(indexService);
            /*IndexService2 indexService2 = (IndexService2) applicationContext.getBean("indexService2");
            System.out.println(indexService2);*/
            String testServiceImpl = ((TestServiceImpl) ApplicationContextUtil.getBean("testServiceImpl")).hello();
            System.out.println(testServiceImpl);
        }

    看结果

     ok,今天就先到这里,以后有新的内容随时补充吧

  • 相关阅读:
    Golang哲学思想
    Outlook与Hotmail的设置
    Android 经验: 5555 端口会被 adb 误认为 emulator
    QT程序探测所需DLL,静态连接和打包
    VS编译的QT程序发布时产生的AppCrash问题
    新语言和旧语言
    MMU和TLB
    FMX的综合评价
    Windows核心编程学习九:利用内核对象进行线程同步
    QListWidget特别简单,但有两种添加item的方式
  • 原文地址:https://www.cnblogs.com/lusaisai/p/12907402.html
Copyright © 2020-2023  润新知