深入学习Spring——笔记

学习中!!!!!!!!!!!!!!!

3-8

BeanFactory && ApplicationContext

BeanFactory

首先,从SpringBoot的主启动类来看

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
    }
}

在IDEA中将光标放到ConfigurableApplication上,ctrl + alt + u。 可查看该类的相关类图如下:
在这里插入图片描述
可以看到ConfigurableApplication、ApplicationContext、BeanFactory。从图中可以看出ApplicationContext间接实现了BeanFactory而ConfigurableApplication实现ApplicationContext。也就是更核心的其实就是BeanFactory

使用Debug对ConfigableApplication的实例进行查看,可以看到示例中包含beanFactory对象
在这里插入图片描述
然而单纯的看BeanFactory,其名下并没有太多的方法
在这里插入图片描述

最主要的其实是BeanFactory的实现类DefaultListableBeanFactory。其继承、实现的接口、类的情况如下
在这里插入图片描述

虽然BeanFactory表面上看着比较简单,但是实际上控制反转、依赖注入、Bean的生命周期等功能,都是由他的实现类来提供的
以DefaultListableBeanFactory间接继承的父类DefauleSingletonBeanRegistry为例,获取对应的单例bean

 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext run = SpringApplication.run(DemoApplication.class, args);
        System.out.println(run);

        //因为singletonObjects是私有的,所以通过反射,获取DefaultSingletonBeanRegistry类中的名为singletonObjects的属性。
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        //设置私有属性在类外面允许被访问
        singletonObjects.setAccessible(true);
        //获取当前Springboot实例的Bean Factory
        ConfigurableListableBeanFactory beanFactory = run.getBeanFactory();
        //根据beanFactory对象获取其对应的单例Bean的Map 键表示Bean的名称,值表示Bean的实例
        Map<String,Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        //输出key value
        map.forEach((k,v)->System.out.println(k + "=" + v));

    }

可以使用@commpent @service等注解来注入对应的类,这些注解都会被Spring Boot识别,前提是放到类上,不要放到接口上,接口也不能实例化

ApplicationContext

MessageSource: getMessage().主要是读取对应的properties文件,进行一个语言的转化
ResourcePatternResolver:getResources() 读取对应通配符路径下的文件,参数例classpath:application.properties,通配符如:classpath: \ filed:
EnvironmentCapable:getEnvironment() 主要是获取环境中的键值相关的信息,如环境变量、yaml文件中的某个键的值,例run.getEnvironment().getProperty("server.port")
ApplicationEventPublisher:publishEvent()事件监听,主要可以用来解耦合,可以通过@EventListener注解来监听

3-9

BeanFactory && ApplicationContext

BeanFactory的实现

首先,如下测试代码

public class BeanFactoryTest {
    public static void main(String[] args) {
        //创建一个factory实例对象,当前的factory中并没有任何的Bean
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中
        //BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();
        //将定义的Bean加入到factory中,需要为其命名
        factory.registerBeanDefinition("config",beanDefinition);
        //输出已经注入的Bean
        Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);
    }
    @Configuration
    static class Config{
        public Bean1 bean1(){
            return  new Bean1();
        }
        public Bean2 bean2(){
            return new Bean2();
        }
    }
    static class Bean1{
        private static final Logger log   = LoggerFactory.getLogger(Bean1.class);

        public Bean1(){
            log.debug("bean1");
        }
        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }
    }
    static class Bean2{
        private static final Logger log   = LoggerFactory.getLogger(Bean1.class);
        public Bean2(){
            log.debug("bean2");
        }
    }
}

执行该代码后发现,只有我们手动定义的Config被注入到beanfactory中。@Configuration注解、@Bean注解并没有起到作用。由此可以看出,注解标注的类等,并不是有beanfactory直接注入的,而是由别的类来完成

修改后:

    public static void main(String[] args) {
        //创建一个factory实例对象,当前的factory中并没有任何的Bean
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        //Bean的定义(class、scope、初始化、销毁等),定义一些Bean放入到factory中
        //BeanDefinitionBuilder是一个工具类,用于构架一个BeanDefinition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).getBeanDefinition();
        //将定义的Bean加入到factory中,需要为其命名
        factory.registerBeanDefinition("config",beanDefinition);
        //注册注解处理器,注册Spring上下问的注解,向beanFactory中注册所需的注解处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(factory);
        /**
         * BeanFactoryPostProcessor 是一种特殊的 Bean,
         * 用于在 Spring 容器实例化所有其他 Bean 之前,对 BeanFactory 进行修改。
         * 这些修改可能包括添加、修改或删除 Bean 的属性,修改 Bean 的定义等
         */
        //获取BeanFactoryPostProcessor相关的已经注入的Bean,@Configuration、@Autowired、@PostConstruct、@PreDestroy等注解都属于该类型
        factory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(item->{
            item.postProcessBeanFactory(factory);
        });
        Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);
    }

但是在该代码的基础上,调用factory.getBean(Bean1.class).getBean2()方法,得到的结果是null,因为getBean2返回的是一个Bean2对象,而在Bean1的class中,Bean2对象使用的是@Autowired注解进行注入,也就表示,该注入并未成功。也就表示BeanFactoryPostProcessor.class没有对@Autowired进行处理。
修改后如下:


//bean后置处理器,针对的是Bean的生命周期的各个阶段提供扩展。如@Autowired、@Resource等
        factory.getBeansOfType(BeanPostProcessor.class).values().forEach(factory::addBeanPostProcessor);
        System.out.println(factory.getBean(Bean1.class).getBean2());
        Arrays.stream(factory.getBeanDefinitionNames()).forEach(System.out::println);

BeanFactoryPostProcessor 针对的是Bean工厂,先将其加入Bean工厂,BeanPostProcessor针对的是Bean ,再与Bean建立联系

以@Autowired 和 @Resource 为例

在上述代码基础上,加入
    interface Inter {
    }

    static class Bean3 implements Inter {

    }

    static class Bean4 implements Inter {

    }
  static class Bean1 {
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1() {
            log.debug("bean1");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2() {
            return bean2;
        }

        @Autowired
        private Inter inter;
        public Inter getInter() {
            return inter;
        }
    }

首先对Inter 接口使用@Autowired进行注入,之后调用getInteger()方法

System.out.println(factory.getBean(Bean1.class).getInter());

会出现该错误
在这里插入图片描述
因为@Autowired注解,会先根据类型去查找,之后再回根据类型进行查找。在这个例子中,@Autowired注解先根据类型找到了Bean3和Bean4(这两个都是实现了Inter接口),之后因为没有唯一的实现,所以会根据名字去查找,而此时的命名为Inter inter ,所以@Autowired找不到对应的类进行注入,就会抛出异常。
在此可以使用两种解决方法:

  • 将Inter inter 命名改为 Inter bean3 或 Inter bean4 ,指明要注入额Bean的名称,由此找到对应的类。

  • 使用@Resource注解指定具体的name

     @Resource(name = "bean3")
     private Inter inter;
    

如果两种注解同时使用的话,情况分析::::::

@Resource(name = "bean3")
   @Autowired
   private Inter inter;

此时仍会抛出异常
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type ‘com.example.demo.test.BeanFactoryTest$Inter’ available: expected single matching bean but found 2: bean3,bean4
其原因是因为@Autowired的优先级高于@Resource,所以@Autowired生效了

 //bean后置处理器,针对的是Bean的生命周期的各个阶段提供扩展。如@Autowired、@Resource等
  factory.getBeansOfType(BeanPostProcessor.class).values().stream().forEach(item->{
            System.out.println(item);
            factory.addBeanPostProcessor(item);
        });

在该代码出加个输出,即在将后置处理器加入BeanPostProcessor时,进行一个输出,看一下先后顺序,结果如下

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@1e683a3e
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@2053d869

由此可以看出@Autowired的优先级高于@Resource
因为在将这些后置处理器加入到BeanPostProcessor是,有一个优先级的先后顺序,也可以人为的进行改变。如下::::

     factory.getBeansOfType(BeanPostProcessor.class).values()
                .stream().sorted(factory.getDependencyComparator()).
                forEach(item->{
            System.out.println(item);
            factory.addBeanPostProcessor(item);
        });

执行结果:::::

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@3e84448c
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@4a7f959b

是因为,在CommonAnnotationBeanPostProcessor类和AutowiredAnnotationBeanPostProcessor类中,有一个优先级的字段order,比较器会根据order的大小进行优先级排序

CommonAnnotationBeanPostProcessor:::
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
AutowiredAnnotationBeanPostProcessor:::
private int order = Ordered.LOWEST_PRECEDENCE - 2;

由此可以看出CommonAnnotationBeanPostProcessor对应的值小,所以优先级高,因此人为排序后的@Resource的优先级大于@Autowried。

3-14

Bean的生命周期

Bean流程测试

@Component
public class LifeCycleBeanTest {
    private static final Logger log = LoggerFactory.getLogger(LifeCycleBeanTest.class);

    public LifeCycleBeanTest() {
        log.debug("构造方法");
    }
    @Autowired
    public void autowire(@Value("${JAVA_HOME}") String javacHome){
        log.debug("依赖注入:{}",javacHome);
    }
    @PostConstruct
    public void init(){
        log.debug("初始化");
    }
    @PreDestroy
    public void destroy(){
        log.debug("销毁");
    }
}

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
        run.close();
    }
}

创建方法后进行debug,可以看到输出如下:
com.example.demo.test.LifeCycleBeanTest : 构造方法
com.example.demo.test.LifeCycleBeanTest : 依赖注入
com.example.demo.test.LifeCycleBeanTest : 初始化
com.example.demo.test.LifeCycleBeanTest : 销毁

也就是当一个类加上Component注解后,进行扫描时,会先执行其构造方法也就是实例化。之后会对相关的加有依赖注入的注解进行依赖注入,如果有@PostConstruct注解,表示在初始化时进行一些操作,@PreDestroy表示在这个实例销毁时进行一些操作

使用后置处理器对Bean进行操作

可以在Bean的实例化、依赖注入、初始化、销毁等操作时,对其进行一些额外的操作,如下:

@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {
    private static final Logger log = LoggerFactory.getLogger(MyBeanPostProcessor.class);
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<销毁前执行,如@PreDestory>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        }
    }

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<实例化之前执行,在这里返回的对象可以替换掉原来的bean>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        }
        return  null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<实例化之后执行,如果这里返回false会跳过依赖注入阶段>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            return false;
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<依赖注入阶段执行,例如:@Autowired、@Value、@Resource>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        }
        return pvs;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<初始化之前执行,返回对象可替换原本的bean,如@PostConstruct 、@ConfigurationProperties>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if(beanName.equals("lifeCycleBeanTest")){
            log.debug("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<初始化之后执行,返回的对象会替换掉原本的bean,如代理增强>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        }
        return bean;
    }
}

3-15

后置处理器

bean后置处理器

创建Bean1、Bean2、Bean3

public class Bean1 {
    private static final Logger log = LoggerFactory.getLogger(Bean1.class);

    private Bean2 bean2;

    public Bean1() {
        log.debug("Bean1无参构造");
    }
    @Autowired
    public void setBean2(Bean2 bean2) {
        log.debug("@Autowired生效:{}", bean2);
        this.bean2 = bean2;
    }

    private Bean3 bean3;

    @Resource
    public void setBean3(Bean3 bean3) {
        log.debug("@Resource生效:{}", bean3);
        this.bean3 = bean3;
    }

    private String home;

    @Autowired
    public void setHome(@Value("${JAVA_HOME}") String home) {
        log.debug("@Value生效:{}",home);
        this.home = home;
    }
    @PostConstruct
    public void init(){
        log.debug("@PostConstruct生效");
    }

    @PreDestroy
    public void destroy(){
        log.debug("@PreDestroy生效");
    }
}
public class Bean2 {
}
public class Bean3 {
}

主启动类

public class Application {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        //注册Bean1 、 Bean2 、 Bean3
        context.registerBean("bean1", Bean1.class);
        context.registerBean("bean2", Bean2.class);
        context.registerBean("bean3", Bean3.class);
        context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        //Autowired等注解的后置处理器,去掉后就不会对Autowired进行自动注入
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        //@Resource 、@PostConstruct、 @PreDestroy等注解的后置处理器。。。。。
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.refresh();
        context.close();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值