精华内容
下载资源
问答
  • 根据@Autowired注解的源码,可以看到该注解可以作用在构造器、参数、方法、属性,都是从容器中获取参数组件的值 标注在方法上:@Bean+方法参数,参数从容器中获取,默认不写@Autowired效果是一样的,都能自动装配 ...

    目录

     

    一、概述

    二、实例分析

    三、源码追踪

    四、总结


    一、概述

    【1】注解用法

    根据@Autowired注解的源码,可以看到该注解可以作用在构造器、参数、方法、属性,都是从容器中获取参数组件的值

    • 标注在方法上:@Bean+方法参数,参数从容器中获取,默认不写@Autowired效果是一样的,都能自动装配
    • 标注在构造器上:如果组件上只有一个有参构造,这个有参构造的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
    • 标注在参数位置
    • 标注在属性位置
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        boolean required() default true;
    }
    

    相关注解:

    • @Autowired:默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用(Spring提供)
    • @Qualifier():指定装配的bean,多个实例时可以结合@Autowired一起使用
    • @Primary:自动装配时当出现多个bean候选者时,被注解为@Primary的bean将作为首选者
    • @Resource:默认按名称装配,当找不到与名称匹配的bean才会按类型装配(不支持@Primary@Autowired(required = false)功能,JDK提供)
    • @Inject:需要导入javax.inject的包,和Autowired功能一样,但是没有required=false功能(JDK提供)

    【2】自动装配

    Spring利用依赖注入(DI)完成对IOC容器中各个组件的依赖关系赋值

    @Autowired自动注入(Spring提供的):

    • 默认优先按照去容器中找对应的组件:applicationContext.getBean()
    • 如果找到多个相同类型的组件,再将属性的名称作为组件的ID去容器中查找
    • @Qualifier()注解:该注解指定需要装配的组件ID,而不是使用属性名
    • 自动装配默认必须要对属性赋值,没有就会报错,可以使用@Autowired(required = false)指定非必须就不会报错
    • @Primary注解:自动装配时当出现多个bean候选者时,被注解为@Primary的bean将作为首选者,否则将抛出异常,如果使用了@Qualifier()指定装配的bean,则还是使用明确指定装配的bean

    @Resource(JSR250)和@Inject(JSR330)(JDK提供的)

    @Resource:

    • 默认按照组件名称进行装配,也可以指定名称进行装配
    • 当找不到与名称匹配的bean会按类型装配
    • 不支持@Primary@Autowired(required = false)功能
    • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
    • 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
    • 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

    @Inject:

    • 需要导入javax.inject的包,和Autowired功能一样,但是没有required=false功能

    【3】@Autowired和@Resource注解的区别

    • @Autowired由Spring提供,只按照byType注入;@Resource由J2EE提供,默认按照byName自动注入,当找不到与名称匹配的bean会按类型装配
    • @Autowired默认按类型装配,默认情况下必须要求依赖对象存在,如果要允许null值,可以设置它的required属性为false。如果想使用名称装配可以结合@Qualifier注解进行使用。
    • @Resource,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    二、实例分析

    这里只对@Autowired注解标注在属性位置进行实例分析

    【1】@Autowired注解

    // 启动类
    @Test
    public void TestMain() {
        // 创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = applicationContext.getBean(UserService.class);
        System.out.println("userService:" + userService);
    }
    
    // Service
    @Service
    public class UserService {
        @Autowired(required = false)	// 指定非必须
        @Qualifier("userDao2")		// 指定装配bean
        private UserDao userDao;
        @Override
        public String toString() {
            return "UserService{" +
                    "userDao=" + userDao +
                    '}';
        }
    }
    
    // Dao
    @Repository
    public class UserDao {
        private String label = "1";
        public void setLabel(String label) {
            this.label = label;
        }
        @Override
        public String toString() {
            return "UserDao{" +
                    "label='" + label + '\'' +
                    '}';
        }
    }
    
    // 配置类
    @Configuration
    @ComponentScan({"dao","service","controller"})
    public class AppConfig {
        @Primary		// 首选装配bean
        @Bean("userDao2")
        public UserDao userDao(){
            UserDao userDao = new UserDao();
            userDao.setLabel("2");
            return userDao;
        }
    }
    

    输出结果如下,由于上面使用@Qualifier("userDao2")指定了要装配的bean,所以这里输出的是label=’2‘:

    image-20210313102341875

    • 如果将@Qualifier("userDao2")改为@Qualifier("userDao"),则装配的是label=’1‘

    【2】@Resource注解

    @Service
    public class UserService {
        @Resource(name = "userDao2",type = UserDao.class)
        private UserDao userDao;
        @Override
        public String toString() {
            return "UserService{" +
                    "userDao=" + userDao +
                    '}';
        }
    }
    
    • 默认按照组件名称进行装配,也可以指定名称进行装配
    • 当找不到与名称匹配的bean会按类型装配
    • 不支持@Primary@Autowired(required = false)功能
    • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
    • 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
    • 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。

    三、源码追踪

    这里对@Autowired注解底层进行源码分析

    参考:https://blog.csdn.net/topdeveloperr/article/details/87971446

    @Autowired是用来装配bean的,肯定和bean的实例化有关,先经过了refresh方法,在finishBeanFactoryInitialization方法中getBean,然后走getObject的时候触发bean的初始化。bean的初始化是一个很复杂地方,在AbstractAutowireCapableBeanFactory#doCreateBean方法中,先创建一个BeanWrapper,它的内部成员变量wrappedObject中存放的就是实例化的MyService对象,Spring Bean的生命周期源码详解 - 【Spring底层原理】,再往后进入populateBean方法进行属性注入

    Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor#postProcessProperties之中,——>findAutowiringMetadata——>buildAutowiringMetadata,核心代码就在buildAutowiringMetadata方法里面

    private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
        if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
            return InjectionMetadata.EMPTY;
        } else {
            List<InjectedElement> elements = new ArrayList();
            // 需要处理的目标类
            Class targetClass = clazz;
    
            do {
                List<InjectedElement> currElements = new ArrayList();
                // 通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性
                ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
                    MergedAnnotation<?> ann = this.findAutowiredAnnotation(field);
                    if (ann != null) {
                        // 校验autowired注解是否用在了static方法上
                        if (Modifier.isStatic(field.getModifiers())) {
                            if (this.logger.isInfoEnabled()) {
                                this.logger.info("Autowired annotation is not supported on static fields: " + field);
                            }
    
                            return;
                        }
    
                        // 判断是否指定了required
                        boolean required = this.determineRequiredStatus(ann);
                        currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
                    }
    
                });
                // 和上面一样的逻辑,但是是通过反射处理类的method
                ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                    if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
                        MergedAnnotation<?> ann = this.findAutowiredAnnotation(bridgedMethod);
                        if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
                            if (Modifier.isStatic(method.getModifiers())) {
                                if (this.logger.isInfoEnabled()) {
                                    this.logger.info("Autowired annotation is not supported on static methods: " + method);
                                }
    
                                return;
                            }
    
                            if (method.getParameterCount() == 0 && this.logger.isInfoEnabled()) {
                                this.logger.info("Autowired annotation should only be used on methods with parameters: " + method);
                            }
    
                            boolean required = this.determineRequiredStatus(ann);
                            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                            currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
                        }
    
                    }
                });
                // 用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理
                elements.addAll(0, currElements);
                targetClass = targetClass.getSuperclass();
            } while(targetClass != null && targetClass != Object.class);
    
            return InjectionMetadata.forElements(elements, clazz);
        }
    }
    
    • 获取需要处理的目标类
    • 通过doWithLocalFields方法传入目标类参数,通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性
    • 判断autowired注解是否用在了static方法上
    • 如有多个@Autowired修饰的注解,都加在currElements这个容器里面,一起处理

    最后返回包含所有带有autowire注解修饰的一个InjectionMetadata集合,如下

    • targetClass:要处理的目标类
    • elements:上述方法获取到的所以elements集合
    public InjectionMetadata(Class<?> targetClass, Collection<InjectionMetadata.InjectedElement> elements) {
        this.targetClass = targetClass;
        this.injectedElements = elements;
    }
    

    有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:

    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
        if (!this.validatedBeanNames.contains(beanName)) {
            if (!this.shouldSkip(this.beanFactory, beanName)) {
                List<String> invalidProperties = new ArrayList();
                PropertyDescriptor[] var6 = pds;
                int var7 = pds.length;
    
                for(int var8 = 0; var8 < var7; ++var8) {
                    PropertyDescriptor pd = var6[var8];
                    if (this.isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
                        invalidProperties.add(pd.getName());
                    }
                }
    
                if (!invalidProperties.isEmpty()) {
                    throw new BeanInitializationException(this.buildExceptionMessage(invalidProperties, beanName));
                }
            }
    
            this.validatedBeanNames.add(beanName);
        }
    
        return pvs;
    }
    

    调用InjectionMetadata中定义的inject方法:

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
        Collection<InjectionMetadata.InjectedElement> checkedElements = this.checkedElements;
        Collection<InjectionMetadata.InjectedElement> elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;
        if (!((Collection)elementsToIterate).isEmpty()) {
            Iterator var6 = ((Collection)elementsToIterate).iterator();
    
            while(var6.hasNext()) {
                InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();
                element.inject(target, beanName, pvs);
            }
        }
    }
    

    进行遍历,然后调用inject方法,inject方法其实现逻辑如下:

    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable {
        if (this.isField) {
            Field field = (Field)this.member;
            // 暴力破解的方法,通过反射技术对对象进行实例化和赋值
            ReflectionUtils.makeAccessible(field);
            field.set(target, this.getResourceToInject(target, requestingBeanName));
        } else {
            if (this.checkPropertySkipping(pvs)) {
                return;
            }
    
            try {
                Method method = (Method)this.member;
                ReflectionUtils.makeAccessible(method);
                // 注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它
                method.invoke(target, this.getResourceToInject(target, requestingBeanName));
            } catch (InvocationTargetException var5) {
                throw var5.getTargetException();
            }
        }
    }
    
    • 使用了反射技术,分成字段和方法去处理的。
    • makeAccessible这样的可以称之为暴力破解的方法,通过反射技术对对象进行实例化和赋值
    • getResourceToInject方法的参数就是要注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它

    四、总结

    @AutoWired自动注入过程图:

    image-20210313173345709

     

    展开全文
  • @Autowired注解用法 在分析这个注解的实现原理之前,我们不妨先来回顾一下@Autowired注解的用法。 将@Autowired注解应用于构造函数,如以下示例所示 public class MovieRecommender { private final ...

    上一篇:深夜看了张一鸣的微博,让我越想越后怕

    前言

    使用spring开发时,进行配置主要有两种方式,一是xml的方式,二是java config的方式。

    spring技术自身也在不断的发展和改变,从当前springboot的火热程度来看,java config的应用是越来越广泛了,在使用java config的过程当中,我们不可避免的会有各种各样的注解打交道,其中,我们使用最多的注解应该就是@Autowired注解了。这个注解的功能就是为我们注入一个定义好的bean。

    那么,这个注解除了我们常用的属性注入方式之外还有哪些使用方式呢?它在代码层面又是怎么实现的呢?这是本篇文章着重想讨论的问题。

    @Autowired注解用法

    在分析这个注解的实现原理之前,我们不妨先来回顾一下@Autowired注解的用法。

    将@Autowired注解应用于构造函数,如以下示例所示

    public class MovieRecommender {
     
        private final CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }
    

    将@Autowired注释应用于setter方法

    public class SimpleMovieLister {
     
        private MovieFinder movieFinder;
     
        @Autowired
        public void setMovieFinder(MovieFinder movieFinder) {
            this.movieFinder = movieFinder;
        }
     
        // ...
    }
    

    将@Autowired注释应用于具有任意名称和多个参数的方法

    public class MovieRecommender {
     
        private MovieCatalog movieCatalog;
     
        private CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        public void prepare(MovieCatalog movieCatalog,
                CustomerPreferenceDao customerPreferenceDao) {
            this.movieCatalog = movieCatalog;
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }
    

    您也可以将@Autowired应用于字段,或者将其与构造函数混合,如以下示例所示

    public class MovieRecommender {
     
        private final CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        private MovieCatalog movieCatalog;
     
        @Autowired
        public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }
    

    直接应用于字段是我们使用的最多的一种方式,但是使用构造方法注入从代码层面却是更加好的。除此之外,还有以下不太常见的几种方式

    将@Autowired注释添加到需要该类型数组的字段或方法,则spring会从ApplicationContext中搜寻符合指定类型的所有bean,如以下示例所示:

    public class MovieRecommender {
     
        @Autowired
        private MovieCatalog[] movieCatalogs;
     
        // ...
    }
    

    数组可以,我们可以马上举一反三,那容器也可以吗,答案是肯定的,下面是set以及map的例子:

    public class MovieRecommender {
     
        private Set<MovieCatalog> movieCatalogs;
     
        @Autowired
        public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
            this.movieCatalogs = movieCatalogs;
        }
     
        // ...
    }
    public class MovieRecommender {
     
        private Map<String, MovieCatalog> movieCatalogs;
     
        @Autowired
        public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
            this.movieCatalogs = movieCatalogs;
        }
     
        // ...
    }
    

    以上就是@Autowired注解的主要使用方式,经常使用spring的话应该对其中常用的几种不会感到陌生。

    @Autowired注解的作用到底是什么

    @Autowired这个注解我们经常在使用,现在,我想问的是,它的作用到底是什么呢?

    首先,我们从所属范围来看,事实上这个注解是属于spring的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier等等。因此@Autowired注解是一个用于容器(container)配置的注解。

    其次,我们可以直接从字面意思来看,@autowired注解来源于英文单词autowire,这个单词的意思是自动装配的意思。自动装配又是什么意思?这个词语本来的意思是指的一些工业上的用机器代替人口,自动将一些需要完成的组装任务,或者别的一些任务完成。而在spring的世界当中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起。

    因此,笔者个人对这个注解的作用下的定义就是:将Spring容器中的bean自动的和我们需要这个bean的类组装在一起协同使用。

    接下来,我们就来看一下这个注解背后到底做了些什么工作。

    @Autowired注解是如何实现的

    事实上,要回答这个问题必须先弄明白的是java是如何支持注解这样一个功能的。

    java的注解实现的核心技术是反射,让我们通过一些例子以及自己实现一个注解来理解它工作的原理。

    例如注解@Override

    @Override注解的定义如下:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    @Override注解使用java官方提供的注解,它的定义里面并没有任何的实现逻辑。注意,所有的注解几乎都是这样的,注解只能是被看作元数据,它不包含任何业务逻辑。 注解更像是一个标签,一个声明,表面被注释的这个地方,将具有某种特定的逻辑。

    那么,问题接踵而至,注解本身不包含任何逻辑,那么注解的功能是如何实现的呢?答案必然是别的某个地方对这个注解做了实现。以@Override注解为例,他的功能是重写一个方法,而他的实现者就是JVM,java虚拟机,java虚拟机在字节码层面实现了这个功能。

    但是对于开发人员,虚拟机的实现是无法控制的东西,也不能用于自定义注解。所以,如果是我们自己想定义一个独一无二的注解的话,则我们需要自己为注解写一个实现逻辑,换言之,我们需要实现自己注解特定逻辑的功能。

    在自己写注解之前我们有一些基础知识需要掌握,那就是我们写注解这个功能首先是需要java支持的,java在jdk5当中支持了这一功能,并且在java.lang.annotation包中提供了四个注解,仅用于编写注解时使用,他们是:

    下面我们开始自己实现一个注解,注解仅支持 primitivesstring和 enumerations这三种类型。注解的所有属性都定义为方法,也可以提供默认值。我们先实现一个最简单的注解。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
     
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SimpleAnnotation {
        String value();
    }
    

    上面这个注释里面只定义了一个字符传,它的目标注释对象是方法,保留策略是在运行期间。下面我们定义一个方法来使用这个注解:

    public class UseAnnotation {
     
        @SimpleAnnotation("testStringValue")
        public void testMethod(){
            //do something here
        }
     
    }
    

    我们在这里使用了这个注解,并把字符串赋值为:testStringValue,到这里,定义一个注解并使用它,我们就已经全部完成。

    简单的不敢相信。但是,细心一想的话,我们虽然写了一个注解也用了它,可是它并没有产生任何作用啊。也没有对我们这里方法产生任何效果啊。是的现在确实是这样的,原因在于我们前面提到的一点,我们还没有为这个注解实现它的逻辑,现在我们就来为这个注解实现逻辑。

    应该怎么做呢?我们不妨自己来想一想。首先,我想给标注了这个注解的方法或字段实现功能,我们必须得知道,到底有哪些方法,哪些字段使用了这个注解吧,因此,这里我们很容易想到,这里应该会用到反射。

    其次,利用反射,我们利用反射拿到这样目标之后,得为他实现一个逻辑,这个逻辑是这些方法本身逻辑之外的逻辑,这又让我们想起了代理,aop等知识,我们相当于就是在为这些方法做一个增强。事实上的实现主借的逻辑也大概就是这个思路。梳理一下大致步骤如下:

    现在我们来实现一下这个逻辑,代码如下:

    private static void annotationLogic() {
    
         Class useAnnotationClass = UseAnnotation.class;
         for(Method method : useAnnotationClass.getMethods()) {
             SimpleAnnotation simpleAnnotation = (SimpleAnnotation)method.getAnnotation(SimpleAnnotation.class);
             if(simpleAnnotation != null) {
                 System.out.println(" Method Name : " + method.getName());
                 System.out.println(" value : " + simpleAnnotation.value());
                 System.out.println(" --------------------------- ");
             }
         }
     }
    

    在这里我们实现的逻辑就是打印几句话。

    从上面的实现逻辑我们不能发现,借助于java的反射我们可以直接拿到一个类里所有的方法,然后再拿到方法上的注解,当然,我们也可以拿到字段上的注解。借助于反射我们可以拿到几乎任何属于一个类的东西。

    一个简单的注解我们就实现完了。现在我们再回过头来,看一下@Autowired注解是如何实现的。另外,Spring 系列面试题和答案全部整理好了,微信搜索互联网架构师,在后台发送:2T,可以在线阅读。

    @Autowired注解实现逻辑分析

    知道了上面的知识,我们不难想到,上面的注解虽然简单,但是@Autowired和他最大的区别应该仅仅在于注解的实现逻辑,其他利用反射获取注解等等步骤应该都是一致的。

    先来看一下@Autowired这个注解在spring的源代码里的定义是怎样的,如下所示:

    package org.springframework.beans.factory.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.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        boolean required() default true;
    }
    

    阅读代码我们可以看到,Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。下面,我们不多说直接来看spring对这个注解进行的逻辑实现。

    在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,该包的内容如下:

    经过分析,不难发现Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor之中,已在上图标红。

    其中的核心处理代码如下:

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
      LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
      Class<?> targetClass = clazz;//需要处理的目标类
           
      do {
       final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
     
                /*通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性*/  
     
       ReflectionUtils.doWithLocalFields(targetClass, field -> {
        AnnotationAttributes ann = findAutowiredAnnotation(field);
        if (ann != null) {//校验autowired注解是否用在了static方法上
         if (Modifier.isStatic(field.getModifiers())) {
          if (logger.isWarnEnabled()) {
           logger.warn("Autowired annotation is not supported on static fields: " + field);
          }
          return;
         }//判断是否指定了required
         boolean required = determineRequiredStatus(ann);
         currElements.add(new AutowiredFieldElement(field, required));
        }
       });
                //和上面一样的逻辑,但是是通过反射处理类的method
       ReflectionUtils.doWithLocalMethods(targetClass, method -> {
        Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
        if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
         return;
        }
        AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
        if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
         if (Modifier.isStatic(method.getModifiers())) {
          if (logger.isWarnEnabled()) {
           logger.warn("Autowired annotation is not supported on static methods: " + method);
          }
          return;
         }
         if (method.getParameterCount() == 0) {
          if (logger.isWarnEnabled()) {
           logger.warn("Autowired annotation should only be used on methods with parameters: " +
             method);
          }
         }
         boolean required = determineRequiredStatus(ann);
         PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                       currElements.add(new AutowiredMethodElement(method, required, pd));
        }
       });
        //用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理  
       elements.addAll(0, currElements);
       targetClass = targetClass.getSuperclass();
      }
      while (targetClass != null && targetClass != Object.class);
     
      return new InjectionMetadata(clazz, elements);
     }
    

    博主在源代码里加了注释,结合注释就能看懂它做的事情了,最后这个方法返回的就是包含所有带有autowire注解修饰的一个InjectionMetadata集合。这个类由两部分组成:

    public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
      this.targetClass = targetClass;
      this.injectedElements = elements;
     }
    

    一是我们处理的目标类,二就是上述方法获取到的所以elements集合。

    有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:

    @Override
    public PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    
     InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
     try {
      metadata.inject(bean, beanName, pvs);
     }
     catch (BeanCreationException ex) {
      throw ex;
     }
     catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
     }
     return pvs;
    }
    

    它调用的方法是InjectionMetadata中定义的inject方法,如下

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      Collection<InjectedElement> checkedElements = this.checkedElements;
      Collection<InjectedElement> elementsToIterate =
        (checkedElements != null ? checkedElements : this.injectedElements);
      if (!elementsToIterate.isEmpty()) {
       for (InjectedElement element : elementsToIterate) {
        if (logger.isTraceEnabled()) {
         logger.trace("Processing injected element of bean '" + beanName + "': " + element);
        }
        element.inject(target, beanName, pvs);
       }
      }
     }
    

    其逻辑就是遍历,然后调用inject方法,inject方法其实现逻辑如下:

    /**
     * Either this or {@link #getResourceToInject} needs to be overridden.
     */
    protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
      throws Throwable {
    
     if (this.isField) {
      Field field = (Field) this.member;
      ReflectionUtils.makeAccessible(field);
      field.set(target, getResourceToInject(target, requestingBeanName));
     }
     else {
      if (checkPropertySkipping(pvs)) {
       return;
      }
      try {
       Method method = (Method) this.member;
       ReflectionUtils.makeAccessible(method);
       method.invoke(target, getResourceToInject(target, requestingBeanName));
      }
      catch (InvocationTargetException ex) {
       throw ex.getTargetException();
      }
     }
    }
    

    在这里的代码当中我们也可以看到,是inject也使用了反射技术并且依然是分成字段和方法去处理的。在代码里面也调用了makeAccessible这样的可以称之为暴力破解的方法,但是反射技术本就是为框架等用途设计的,这也无可厚非。

    对于字段的话,本质上就是去set这个字段的值,即对对象进行实例化和赋值,例如下面代码:

    @Autowired
    ObjectTest objectTest;
    

    那么在这里实现的就相当于给这个objecTest引用赋值了。

    对于方法的话,本质就是去调用这个方法,因此这里调用的是method.invoke.

    getResourceToInject方法的参数就是要注入的bean的名字,这个方法的功能就是根据这个bean的名字去拿到它。

    以上,就是@Autowire注解实现逻辑的全部分析。结合源代码再看一遍的话,会更加清楚一点。下面是spring容器如何实现@AutoWired自动注入的过程的图:

    总结起来一句话:使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,也就是将其赋为期望的类实例。

    问题

    注解的有效周期是什么?

    各种注释之间的第一个主要区别是,它们是在编译时使用,然后被丢弃(如@Override),还是被放在编译的类文件中,并在运行时可用(如Spring的@Component)。这是由注释的“@Retention”策略决定的。如果您正在编写自己的注释,则需要决定该注释在运行时(可能用于自动配置)还是仅在编译时(用于检查或代码生成)有用。

    当用注释编译代码时,编译器看到注释就像看到源元素上的其他修饰符一样,比如访问修饰符(public/private)或.。当遇到注释时,它运行一个注释处理器,就像一个插件类,表示对特定的注释感兴趣。注释处理器通常使用反射API来检查正在编译的元素,并且可以简单地对它们执行检查、修改它们或生成要编译的新代码。

    @Override是一个示例;它使用反射API来确保能够在其中一个超类中找到方法签名的匹配,如果不能,则使用@Override会导致编译错误。

    注入的bean和用它的bean的关系是如何维护的?

    无论以何种方式注入,注入的bean就相当于类中的一个普通对象应用,这是它的实例化是spring去容器中找符合的bean进行实例化,并注入到类当中的。他们之间的关系就是普通的一个对象持有另一个对象引用的关系。只是这些对象都是spring当中的bean而已。

    为什么注入的bean不能被定义为static的?

    从设计的角度来说 ,使用静态字段会鼓励使用静态方法。静态方法是evil的。依赖注入的主要目的是让容器为您创建对象并进行连接。而且,它使测试更加容易。

    一旦开始使用静态方法,您就不再需要创建对象的实例,并且测试变得更加困难。同样,您不能创建给定类的多个实例,每个实例都注入不同的依赖项(因为该字段是隐式共享的,并且会创建全局状态)。

    静态变量不是Object的属性,而是Class的属性。spring的autowire是在对象上完成的,这样使得设计很干净。在spring当中我们也可以将bean对象定义为单例,这样就能从功能上实现与静态定义相同的目的。

    但是从纯粹技术的层面,我们可以这样做:

    将@Autowired可以与setter方法一起使用,然后可以让setter修改静态字段的值。但是这种做法非常不推荐。

    原文链接:https://blog.csdn.net/topdeveloperr/article/details/87971446

    感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

        · END ·

    最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

    正文结束

    推荐阅读 ↓↓↓

    1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

    2.如何才能成为优秀的架构师?

    3.从零开始搭建创业公司后台技术栈

    4.程序员一般可以从什么平台接私活?

    5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

    6.IntelliJ IDEA 2019.3 首个最新访问版本发布,新特性抢先看

    7.这封“领导痛批95后下属”的邮件,句句扎心!

    8.15张图看懂瞎忙和高效的区别!

    一个人学习、工作很迷茫?

    点击「阅读原文」加入我们的小圈子!

    展开全文
  • @Autowired注解的三种方式如下,第一种是直接在属性名上加注解,这样就可以不用在写set方法进行注入,这种方式与set方式作用一样;第二种是在set方法上加注解;第三种是在构造器上加注解 我们从@Autowired这个注解点...

    简介及源码

    @Autowired注解的三种方式如下,第一种是直接在属性名上加注解,这样就可以不用在写set方法进行注入,这种方式与set方式作用一样;第二种是在set方法上加注解;第三种是在构造器上加注解

    我们从@Autowired这个注解点进去看一下源码:
    我们可以发现这个注解可以标注的位置有:构造器,参数,方法,属性;都是从容器中来获取参数组件的值。

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
    
    
        /**
         * Declares whether the annotated dependency is required.
         * <p>Defaults to {@code true}.
         */
        boolean required() default true;
    
    
    }
    

    标注在方法上

    @Autowired注解标注在方法上:类似于xml配置中的set方法注入
    用的最多的方式就是在@Bean注解标注的方法上标注,但是可省略。@Autowired注解作用在方法上
    (1)该方法如果有参数,会使用autowired的方式在容器中查找是否有该参数
    (2)会执行该方法
    @Autowired作用在普通方法上,会在注入的时候调用一次该方法,如果方法中有实体参数,会对方法里面的参数进行装配,并调用一次该方法。这个可以用来在自动注入的时候做一些初始化操作

    @Component
    public class Boss {
    
    
        private Car car;
    
    
        public Car getCar() {
            return car;
        }
    
    
        @Autowired //标注在方法上,Spring容器在创建当前对象的时候,就会调用当前方法完成赋值;
        //方法使用的参数,自定义类型的值从IOC容器里面进行获取
        public void setCar(Car car) {
            this.car = car;
        }
    
    
        @Override
        public String toString() {
            return "Boss{" +
                    "car=" + car +
                    '}';
        }
    }
    

    标注在构造器上

    @Autowired注解标注在构造器上,默认加载IOC容器中的组件,容器启动的时候会调用无参构造器创建对象,再进行初始化赋值操作,构造器要用的组件,也都是从容器中来获取:
    注意:如果组件只有一个有参的构造器,这个有参的构造器的 @Autowired注解可以省略,参数位置的组件还是可以自动从容器中获取

    //默认加在IOC容器中的组件,容器启动的时候会调用无参构造器创建对象,再进行初始化赋值操作
    @Component
    public class Boss {
    
    
        private Car car;
    
    
        //构造器要用的组件,也都是从容器中来获取
        @Autowired
        public Boss(Car car) {
            this.car = car;
            System.out.println("Boss的有参构造器"+car);
        }
    
    
        public Car getCar() {
            return car;
        }
    
    
        @Autowired //标注在方法上,Spring容器在创建当前对象的时候,就会调用当前方法完成赋值;
        //方法使用的参数,自定义类型的值从IOC容器里面进行获取
        public void setCar(Car car) {
            this.car = car;
        }
    
    
        @Override
        public String toString() {
            return "Boss{" +
                    "car=" + car +
                    '}';
        }
    }
    

    标注在方法上和构造器上,感觉都是会在调用方法时,会自动加载装配方法的参数,完成初始化操作。其中方法可以是结合@Bean标注的方法(此时可省略),也可以是普通方法,此时会创建bean后会主动调用该方法完成舒适化操作

    标注在参数上

    @Autowired注解标注在参数上:效果是一样的

    //默认加在IOC容器中的组件,容器启动的时候会调用无参构造器创建对象,再进行初始化赋值操作
    @Component
    public class Boss {
    
    
        private Car car;
    
    
        //构造器要用的组件,也都是从容器中来获取
    
    
        //我们也可以标注在参数上效果是一样的
        public Boss(@Autowired Car car) {
            this.car = car;
            System.out.println("Boss的有参构造器"+car);
        }
    
    
        public Car getCar() {
            return car;
        }
    
    
        @Autowired //标注在方法上,Spring容器在创建当前对象的时候,就会调用当前方法完成赋值;
        //方法使用的参数,自定义类型的值从IOC容器里面进行获取
        public void setCar(Car car) {
            this.car = car;
        }
    
    
        @Override
        public String toString() {
            return "Boss{" +
                    "car=" + car +
                    '}';
        }
    }
    
    

    直接标注在属性上

    本人最常用。在创建对象时会自动注入装配

    总结

    /**
    * 自动装配;
    *        Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值;
    *
    * 1)、@Autowired:自动注入:
    *        1)、默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值
    *        2)、如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
    *                       applicationContext.getBean("bookDao")
    *        3)、@Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
    *        4)、自动装配默认一定要将属性赋值好,没有就会报错;
    *           可以使用@Autowired(required=false);
    *        5)、@Primary:让Spring进行自动装配的时候,默认使用首选的bean;
    *              也可以继续使用@Qualifier指定需要装配的bean的名字
    *        BookService{
    *           @Autowired
    *           BookDao  bookDao;
    *        }
    *
    * 2)、Spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]
    *        @Resource:
    *           可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
    *           没有能支持@Primary功能没有支持@Autowired(reqiured=false);
    *        @Inject:
    *           需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
    *  @Autowired:Spring定义的; @Resource、@Inject都是java规范
    *     
    * AutowiredAnnotationBeanPostProcessor:解析完成自动装配功能; 属于是底层原理为后置处理器      
    *
    * 3)、 @Autowired:构造器,参数,方法,属性;都是从容器中获取参数组件的值
    *        1)、[标注在方法位置]:@Bean+方法参数;参数从容器中获取;默认不写@Autowired效果是一样的;都能自动装配
    *        2)、[标在构造器上]:如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
    *        3)、放在参数位置:
    *        4)、放在属性位置
    *
    * 4)、自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
    *        自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
    *        把Spring底层一些组件注入到自定义的Bean中;
    *        xxxAware:功能使用xxxProcessor;
    *           ApplicationContextAware==》ApplicationContextAwareProcessor;
    *     
    * /       
    
    展开全文
  • Spring 的@Autowired注解

    2021-03-15 01:09:16
    # Spring 的`@Autowired`注解> 原文: [https://javatutorial.net/autowired-annotation-in-spring](https://javatutorial.net/autowired-annotation-in-spring)`@Autowired`注解是实现依赖注入的一种相对较新的...

    # Spring 的`@Autowired`注解

    > 原文: [https://javatutorial.net/autowired-annotation-in-spring](https://javatutorial.net/autowired-annotation-in-spring)

    `@Autowired`注解是实现依赖注入的一种相对较新的样式。 它允许您将其他豆注入另一个所需的豆中。 与`@Required`的注解类似,`@Autowired`注解可用于在 setter 方法以及构造函数和属性上“自动装配” bean。

    ![java-featured-image](https://img.kancloud.cn/05/3e/053ee0bb59842d92359246c98f815e0c_780x330.jpg)

    ## setter 方法上的`@Autowired`

    请注意,在 setter 方法上使用`@Autowired`注解时,它会自动摆脱 XML 配置文件中的``元素。 相反,当 Spring 发现使用`@Autowired`注释的 setter 方法时,它将对该特定方法执行按类型“自动装配”。

    让我们看看`@Autowired`在实践中。 更具体地说,在设置方法上使用`@Autowired`。

    ### `ExampleService.java`

    ```java

    public class ExampleService {

    private Employee employee;

    @Autowired

    public void setEmployee(Employee emp) {

    // setting the employee

    employee = emp;

    }

    }

    ```

    ### 分解

    上面的示例中没有什么花哨的。 我们只有一个名为`ExampleService`的服务类,该类具有一个`Employee`类型的实例变量,并且有一个名为`setEmployee(Employee emp)`的设置方法,该方法仅用于设置雇员为参数给出的任何东西。

    感谢`@Autowired`注解,在实例化`ExampleService`时,将`Employee`的实例作为该方法的参数注入。

    ## 构造函数上的`@Autowired`注释

    ```java

    public class ExampleService {

    private Employee employee;

    @Autowired

    public ExampleService(Employee employee) {

    this.employee = employee;

    }

    @Autowired

    public void setEmployee(Employee emp) {

    // setting the employee

    employee = emp;

    }

    }

    ```

    再次感谢`@Autowired`注释,当实例化`ExampleService`时,将`Employee`的实例作为构造函数的参数注入。

    ## 属性上的`@Autowired`注释

    自动装配属性节省了我们的时间和代码行。 怎么样? 好吧,当我们在属性上使用该注解时,这些属性不再需要 getter 和 setter。 酷吧?

    ```java

    public class ExampleService {

    @Autowired

    private Employee employee;

    @Autowired

    public ExampleService(Employee employee) {

    this.employee = employee;

    }

    @Autowired

    public void setEmployee(Employee emp) {

    // setting the employee

    employee = emp;

    }

    }

    ```

    在上面的代码片段中,我们自动连接了名为`employee`的属性。 因此,它不再需要 setter 和 getter 方法。`employee`在创建`ExampleService`时被 Spring 注入。

    ## 可选依赖项

    `@Autowired`也可以是可选的。 像这样:

    ```java

    public class ExampleService {

    @Autowired(required = false)

    private Employee employee;

    @Autowired

    public ExampleService(Employee employee) {

    this.employee = employee;

    }

    @Autowired

    public void setEmployee(Employee emp) {

    // setting the employee

    employee = emp;

    }

    }

    ```

    `required = false`使其不是必需的依赖项。

    我们需要可选依赖项的原因是因为 Spring 希望在构造依赖项 bean 时`@Autowired`的依赖项可用。 否则,将引发错误。 由于`required = false`,我们可以解决此问题。

    ## 总结

    通过使用`@Autowired`注解,我们节省了几行代码,还节省了一些时间,因为我们不需要指定属性和构造函数参数。

    展开全文
  • @Autowired注解详解

    2021-08-01 09:09:13
    关于在构造方法上加@Autowired注解,讲下面几点: 1.带有@Autowired注解(属性required默认为true)的构造方法,在Spring初始化对象实例时,会调用此构造函数,进行对象的实例化。 2.如果构造方法上带有了@Autowired...
  • @Autowired注解用法 在分析这个注解的实现原理之前,我们不妨先来回顾一下@Autowired注解的用法。 将@Autowired注解应用于构造函数,如以下示例所示 public class MovieRecommender { private final ...
  • 在实际工作中,使用IDEA开发时,很多码友都喜欢使用@Autowired注解进行依赖注入,这个时候 IDEA 就会报黄色警告,代码一片warning,代码洁癖的我不允许这么一个不明不白的警告在这里。@Autowired作为Spring的亲儿子...
  • @Resource注解和@Autowired注解都是用来实现依赖注入的。 二、这俩注解的相同点 @Resource注解和@Autowired注解都可以作用在成员变量和方法上。 三、这俩注解的不同点 1、@Resource 1.1 @Resource是JDK提供的...
  • ​如何基于Spring自定义依赖注入注解? 在上一章节,我们分享了@Autowire注解方式的原理以及源码,对AutowiredAnnotationBeanPostProcessor这个类的核心方法做了深入分析,本章将对自定义属性注入进行详细分析。 ...
  • 注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些...
  • 我们平时工作中使用Spring的...而我们注入属性,也是用@Autowired或者@Resource注解来完成依赖注入。 思考一下,如果我们的一个类中有多个构造方法呢?Spring创建这个Bean的时候肯定要使用这个类的构造方法实例化,自
  • @Autowired依赖注入为啥不推荐 引言 使用IDEA开发时,同组小伙伴都喜欢用@Autowired注入,代码一片warning,看着很不...这种注入方式就是在bean的变量上使用注解进行依赖注入。本质上是通过反射的方式直接注入到fi
  • 我们开启Spring服务的时候,它会根据声明先扫描配置文件中的bean(注解配置同理), 再根据bean中类的全限定名去寻找它,一般为我们自己声明的pojo(实体类), 然后这时如果有@Autowired注解则会根据类型寻找其它的被...
  • @Autowired注解能用在static属性吗? 答案是否定的,我们来测试下: 日志信息已经很明确了,表示static不能被@Autowired进行复制。为什么呢?我们现在就来一起了解其原因。 首先将我们的测试环境搭建好, User1类 @...
  • Spring支持注解配置 引入注解依赖 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context=...
  • 2.@Autowired默认按类型(byType)装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称...
  • @Autowired注解的实现

    2021-11-23 09:27:54
    从当前springboot的火热程度来看,java config的应用是越来越广泛了,在使用java config的过程当中,我们不可避免的会有各种各样的注解打交道,其中,我们使用最多的注解应该就是@Autowired注解了。这个注解的功能...
  • @Autowired注解和@Resource注解的注入流程
  • @Autowired
  • 使用@Autowired注解基于字段的依赖注入时,IDEA会出现弱警告,如下: 思考:为什么不推荐使用,这种方式是不是有更好的替代方案。 依赖注入方式 依赖注入有三种方式: 基于字段注入 基于构造器注入 基于...
  • @Autowired注解

    2021-08-08 09:28:16
    @Autowired注解@Autowired注解@Autowired 字段@Autowired 构造方法@Autowired 方法@Autowired与@Resource区别@Autowired@Resource不同点 @Autowired注解 @Autowired 字段 我们可以把 @Autowired 注解标注在类文件中...
  • 手动实现@Autowired注解

    2021-09-09 17:47:16
    ... import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext;...import org.springfra
  • @Autowired(required = false) public void setRedisTemplate(RedisTemplate redisTemplate) { RedisSerializer stringSerializer = new StringRedisSerializer(); redisTemplate.setKeySerializ
  • 一. Springboot 被@Component注解的类调用@Autowired注解的类的元素报空指针异常报错内容如下:Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate ...: Constru...
  • 关于@Component注解下的@Autowired注解下的类注入为null的解决方案 今天在测试一个写完的的工具类时,发现工具类里面使用@Autowired注解自动注入的一个jpa数据库接口怎么测试都是null。 后来到网上找了好多帖子,终于...
  • @Autowired注解作用在方法上 @Autowired注解作用在方法上 (1)该方法如果有参数,会使用autowired的方式在容器中查找是否有该参数 (2)会执行该方法
  • 深入理解@Autowired注解

    2021-06-24 20:05:54
    本文来说下@Autowired注解,这个注解在平时的开发中也是使用的比较多,但是很多人可能也就是仅仅会使用而已,本文来说下其实现原理。 文章目录概述 概述 使用spring开发时,进行配置主要有两种方式,一是xml的方式...
  • SpringBoot中@Component注解无法使用@Autowired注解的问题 一、问题原因 springboot 项目中某些情况下@Component注解下@Autowired的类为null的情况,也就是没注入成功,或者是此类在bean加载之前就被调用了。 二、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,560
精华内容 73,424
关键字:

@autowired注解