首页 > 其他分享 >3_@Autowired注解失效分析

3_@Autowired注解失效分析

时间:2024-06-10 13:45:02浏览次数:11  
标签:初始化 Autowired class Bean context 失效 ApplicationContext 注解 public

1. Aware 接口

Aware 接口提供了一种[内置]的注入手段,可以注入BeanFactory, ApplicationContext。内置的注入和初始化不受扩展功能的影响,总会被执行,因此Spring 框架的内部类常使用它们。

InitializingBean 接口提供了一种[内置]的初始化手段。

Aware的作用就是注入与容器相关的信息,例如:

  1. BeanNameAware: 注入bean的名字
  2. BeanFactoryAware: 注入BeanFactory容器
  3. ApplicationContextAware: 注入ApplicationContext 容器
  4. EmbededValueResolverAware: 注入解析器,解析${}

当某一个Bean实现了Aware的接口,就会在Bean的初始化之前,回调实现的方法setBean():

public class MyBean implements BeanNameAware, ApplicationContextAware, InitializingBean {
    @Override
    public void setBeanName(String name) {
        System.out.println("当前bean"+this+"名字叫:"+name);
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        System.out.println("当前bean" +this+"容器是:"+context);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("当前bean"+this+"执行初始化操作");
    }
}

编写主方法运行:

public class A06ApplicationTest {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("myBean",MyBean.class);
        context.refresh();

        context.close();
    }
}
当前beancom.cherry.a06.MyBean@4d50efb8名字叫:myBean
当前beancom.cherry.a06.MyBean@4d50efb8容器是:org.springframework.context.support.GenericApplicationContext@6debcae2, started on Mon Jun 10 08:06:01 CST 2024
当前beancom.cherry.a06.MyBean@4d50efb8执行初始化操作

明明@Autowired和 @PostConstruct注解可以实现注入bean和初始化bean,为什么还需要实现BeanNameAware, ApplicationContextAware, InitializingBean接口来实现注入和初始化的功能?这是因为:

  1. @Autowired等注解解析要用到@Bean后处理器,属于扩展功能
  2. 而Aware接口属于内置的功能,即使不加任何功能,Spring也能识别
  3. 在某些情况下,扩展功能可能会失效,而内置功能并不会失效

2. @Autowired 失效分析

首先编写一个配置类:

@Configuration
public class MyConfig {

    @Autowired
    public void setApplicationContext(ApplicationContext context){
        System.out.println("注入 ApplicationContext");
    }

    @PostConstruct
    public void init(){
        System.out.println("初始化");
    }
}

编写主方法:

public class A06ApplicationTest {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("myConfig",MyConfig.class);
        context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
        context.registerBean(CommonAnnotationBeanPostProcessor.class);
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.refresh();

        context.close();
    }
}

运行:

注入 ApplicationContext
初始化

紧接着在MyConfig中添加一个Bean工厂后处理器:

// 添加一个Bean工厂后处理器
    @Bean
    public BeanFactoryPostProcessor processor1(){
        return beanFactory -> {
            System.out.println("执行 processor1");
        };
    }

运行:

08:52:42.280 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer -- @Bean method MyConfig.processor1 is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
执行 processor1

我们发现Bean的注入和初始化功能都失效了。

这里首先了解一下context.refresh()方法的执行流程:

  1. 首先找到容器中所有BeanFactoryPostProcessor来执行
  2. 添加Bean的后处理器
  3. 执行初始化所有单例

首先看一下Bean单例创建流程:

image-20240610125227277

Java配置类包含BeanFactoryPostProcessor的情况,因此在创建BeanFactoryPostProcessor的前提是要把配置类创建好,才能调用Bean工厂方法,才能调用BeanFactoryPostProcessor。配置类本身就是一个单例对象,而此时的BeanFactoryPostProcessor还未创建好,这就导致了@Autowired注解失效。变成了下面的执行流程:

image-20240610125711892

解决方法就是直接在配置类中使用Spring内置的Bean注入和初始化方法:

如下面的配置类:

@Configuration
public class MyConfig2 implements InitializingBean, ApplicationContextAware {
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("注入 ApplicationContext");
    }

    @Bean
    public BeanFactoryPostProcessor processor2(){
        return beanFactory -> {
            System.out.println("执行 processor2");
        };
    }
}

修改main方法并运行:

context.registerBean("myConfig2",MyConfig2.class);
注入 ApplicationContext
初始化
13:05:55.772 [main] INFO org.springframework.context.annotation.ConfigurationClassEnhancer -- @Bean method MyConfig2.processor2 is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean javadoc for complete details.
执行 processor2

标签:初始化,Autowired,class,Bean,context,失效,ApplicationContext,注解,public
From: https://www.cnblogs.com/lilyflower/p/18240616

相关文章

  • Spring常用注解,自动扫描装配Bean
    1引入context命名空间(在Spring的配置文件中),配置文件如下:Xml代码xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-2.5.xsd......
  • @Transactional 注解下,事务失效的多种场景
    packagecom.example.api.demo.boke;importcom.example.api.demo.config.exceptions.MyException;importorg.springframework.transaction.annotation.Transactional;/***@Transactional*注解下,事务失效的七种场景*/publicclassTransaction{/**......
  • SpringBoot的常用注解
    Spring知识点总结SpringBoot是否需要独立容器不需要,内置了Tomcat/Jetty等容器。运行SpringBoot几种方式打包用命令或者放到容器中运行用Maven/Gradle插件、执行main方法。SpringloC实现机制工厂模式加反射。SpringBoot配置文件几种格式之间区别.properties和.yml格式,区......
  • @Configuration注解
    @Configuration介绍@Configuration是Spring框架中的一个核心注解,它用于标记一个类为配置类,此类主要用于声明Bean以及应用的配置信息。在Spring容器中,通过扫描带有@Configuration注解的类,可以将其实例化并处理其中定义的Bean。在@Configuration注解的类中,可以使用@Bean注解的方法......
  • spring入门aop和ioc基于注解
    目录用注解代替xml文件中的部分配置请先观看链接用注解代替xml文件中的部分配置在要注册bean的地方添加注解@Component()不指定名字就是类名的首字母小写@Component("name")bean的名字就是括号中指定的值在注册完以后要开始注册扫描<!--重点是开启注解扫描-->......
  • python用于类型注解的库- typing
    一、简介动态语言的灵活性使其在做一些工具,脚本时非常方便,但是同时也给大型项目的开发带来了一些麻烦。自python3.5开始,PEP484为python引入了类型注解(typehints),虽然在pep3107定义了函数注释(functionannotation)的语法,但仍然故意留下了一些未定义的行为.现在已经拥有许......
  • 解决canvas上fillText填充后用clearRect清除失效,文字重叠问题
    最初写的demo:如下图: 文字内容未被清除掉,出现了重叠的问题,尝试了网上说的ctx.save(),ctx.restore(),beginPath()等方法都不好用,后来经过一番查找,终于解决了:改写如下: 在这里需要主要的点就是fillText的方法里参数表示的真正含义: 默认情况下,文本基线是位于文字底部,所......
  • 日志工具类之“根据标记的注解进行指定的字段日志记录-在展示方式上会美观一些”
    一、使用方法在添加、编辑等操作功能时可以使用该方案,在需要记录日志的实体类字段中进行注解标注。并标明对应的字段名二、代码1.使用LoggerUtils工具类生成日志publicJsonResultsavePrice(Priceprice){if(price.getId()!=null){String......
  • Spring-MVC注解支持Ant风格的模糊匹配和Restful风格的接收数据------Spring-MVC框架
    packagecom.alatus.mvc3.controller;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;@ControllerpublicclassIndexController{......
  • java中的注解
    目录定义格式使用类型内置注解元注解自定义注解注解实现定义注解一般用于对程序的说明,想注释一样,但是区别是,注释是给人看的,注解是给程序看的让编译器进行编辑检查的作用,比如:@Override修饰的方法,如果改动了方法签名,将会编译报错格式注解是以@注解名在代码中存在,还可以添加一......