Spring boot

SpringBoot @Autowired解析

2020-11-17  本文已影响0人  三也视界

Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。

从所属范围来看,Autowired 属于spring的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier等等。因此@Autowired注解是一个用于容器(container)配置的注解。其次从字面意思来看,@autowired注解来源于英文单词autowire是自动装配的意思,指的一些工业上的用机器代替人口,自动将一些需要完成的组装任务,或者别的一些任务完成。而在spring中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起。

bean实例化和@Autowired装配过程:

1、一切都是从bean工厂的getBean方法开始的,一旦该方法调用总会返回一个bean实例,无论当前是否存在,不存在就实例化一个并装配,否则直接返回。(Spring MVC是在什么时候开始执行bean的实例化过程的呢?其实就在组件扫描完成之后)
2、实例化和装配过程中会多次递归调用getBean方法来解决类之间的依赖。
3、Spring几乎考虑了所有可能性,所以方法特别复杂但完整有条理。
4、@Autowired最终是根据类型来查找和装配元素的,但是我们设置了<beans default-autowire="byName"/>后会影响最终的类型匹配查找。因为在前面有根据BeanDefinition的autowire类型设置PropertyValue值得一步,其中会有新实例的创建和注册。就是那个autowireByName方法。

Autowired注解

autowired有4种模式,byName、byType、constructor、autodectect


image.png

@Autowired在何处使用

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
CONSTRUCTOR:构造
METHOD:方法
PARAMETER:参数
FIELD:字段
ANNOTATION_TYPE:注解

将@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参数

Autowired注解,只有一个required元素,默认是true,也是就是说这个值能改为false。true和false的意义不同。
require=ture 时,表示解析被标记的字段或方法,一定有对应的bean存在。
require=false 时,表示解析被标记的字段或方法,没有对应的bean存在不会报错。

public @interface Autowired {
    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;

}

不使用xml,而使用注解@Autowire注入一个bean?spring是如何实现的?

首先,要回答这个问题必须弄明白java是如何解析注解的。

java是如何解析注解

我们知道Java和Spring都允许我们创建自定义的注解,在创建注解之后,我们是如何使用的呢?
SpringBoot自定义注解的简单实现

以Autowired为例,可以发现,事实上每一个注解本质上都是一个接口,当我们在某一个类当中用到这个注解的时候,就可以通过反射知道是哪个类用了这个注解。也就能拿到这个类的类名,然后就可以根据类名使用反射机制创建对象。与xml的方式就是一样了。大致步骤如下:

一般过程为下

1、利用反射机制获取一个类的Class对象
2、通过这个class对象可以去获取他的每一个方法method,或字段Field等等
3、Method,Field等类提供了类似于getAnnotation的方法来获取这个一个字段的所有注解
4、拿到注解之后,我们可以判断这个注解是否是我们要实现的注解,如果是则实现注解逻辑
现在我们来实现一下这个逻辑,代码如下:

   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的原理

@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之中,该包的内容如下:

image.png

首先要知道执行AbstractApplicationContext#refresh()方法时会执行obtainFreshBeanFactory()方法,而这个方法执行时,会在
DefaultListableBeanFactory#beanDefinitionNames数组中添加internalAutowiredAnnotationProcessor。而internalAutowiredAnnotationProcessor是和AutowiredAnnotationBeanPostProcessor被一起注册到registerPostProcessor中

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }

此方法使用委派模式进行委派。

    public static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
         ...
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
         ...
    }

getBeanNamesForType 是对前面加载的internalAutowiredAnnotationProcessor进行转换成AutowiredAnnotationBeanPostProcessor然后把返回值postProcessorNames转为priorityOrderedPostProcessors然后注册到registerBeanPostProcessors中

    private static void registerBeanPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {

        for (BeanPostProcessor postProcessor : postProcessors) {
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }

AbstractBeanFactory#beanPostProcessors

    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        // Remove from old position, if any
        this.beanPostProcessors.remove(beanPostProcessor);
        // Track whether it is instantiation/destruction aware
        if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
            this.hasInstantiationAwareBeanPostProcessors = true;
        }
        if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
            this.hasDestructionAwareBeanPostProcessors = true;
        }
        // Add to end of list
        this.beanPostProcessors.add(beanPostProcessor);
    }

到此知道了AutowiredAnnotationBeanPostProcessor的来龙去脉。下面就开下AutowiredAnnotationBeanPostProcessor如何去解析@Autowired。

AutowiredAnnotationBeanPostProcessor解析@Autowired

refresh()执行完registerBeanPostProcessors 方法后,继续执行finishBeanFactoryInitialization(beanFactory);

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        ...
        // Instantiate all remaining (non-lazy-init) singletons.
        beanFactory.preInstantiateSingletons();
    }

这里spring会创建所需要的bean,一般在controller层中引入的service也会在此时依赖加载和创建。

    public void preInstantiateSingletons() throws BeansException {
        if (logger.isTraceEnabled()) {
            logger.trace("Pre-instantiating singletons in " + this);
        }
        for (String beanName : beanNames) {
            RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                       ...
            getBean(beanName);
                      ...
        }
    ...

当执行到我们自定义的controller层时,会在getBean中进行执行autowire解析。

    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
              return createBean(beanName, mbd, args);
}

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {
      ...
      doCreateBean(beanName, mbdToUse, args);
      ...
}

而doCreateBean是真正的创建bean实现,在创建的时候调用了applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
              ...
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            ...
    }

终于在applyMergedBeanDefinitionPostProcessors中看到了我们熟悉的身影BeanPostProcessor

    protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof MergedBeanDefinitionPostProcessor) {
                MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
                bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
            }
        }
    }

getBeanPostProcessors方法获取的就是上文中添加的AutowiredAnnotationBeanPostProcessor的集合beanPostProcessors
则执行我们的想看到的AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

findAutowiringMetadata查询这个beanName中,是否有

    private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
         ...
        metadata = buildAutowiringMetadata(clazz);
         ...
    }

经过分析,不难发现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);
    }

findAutowiredAnnotation(bridgedMethod)找到这个类的autowire注解的类,添加到InjectionMetadata对象中。然后在checkConfigMembers方法中又注册到beanDefinition中。

    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        metadata.checkConfigMembers(beanDefinition);
    }

    public void checkConfigMembers(RootBeanDefinition beanDefinition) {
        Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
        for (InjectedElement element : this.injectedElements) {
            Member member = element.getMember();
            if (!beanDefinition.isExternallyManagedConfigMember(member)) {
                beanDefinition.registerExternallyManagedConfigMember(member);
                checkedElements.add(element);
                if (logger.isTraceEnabled()) {
                    logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
                }
            }
        }
        this.checkedElements = checkedElements;
    }

最后这个方法返回的就是包含所有带有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自动注入的过程的图:

image

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

Autowired注解的一些延伸问题

注解的有效周期是什么?

各种注释之间的第一个主要区别是,它们是在编译时使用,然后被丢弃(如@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修改静态字段的值。但是这种做法非常不推荐

@Resource,@Autowired,@Inject 区别

@Resource,@Autowired,@Inject 这3种都是用来注入bean的。

但它们属于不同的程序中,区别详情参见下表:

ANNOTATION PACKAGE SOURCE 作用域 实现方式 其它
@AutoWired org.springframework.bean.factory,Spring自带的方式 Spring 2.5+ 可以用在构造器、方法、属性、参数、注解上面 通过AutowireAnnotationBeanPostProcessor类实现依赖注入 注入可以根据名字/类型,可以设置required属性为false指定找不到相应bean时不抛异常
@Resource javax.annotation,是JSR-250标准,JDK6以上自带,Spring版本要求2.5以上 Java JSR-250 可以用在方法、属性、类上 通过CommonAnnotationBeanPostProcessor类实现依赖注入 与@AutoWired一致。但可以指定name属性来指定beanName,但如果name对应的bean不存在,则会抛出异常,且没有required属性
@Inject javax.inject,是JSR-303标准,Spring版本3以上。需要导入外部依赖 Java JSR-330 可以用在方法、属性、构造器上 通过AutowiredAnnotationBeanPostProcessor类实现依赖注入 与@AutoWired一致,区别在于@Inject没有required属性

@Inject

如下是@Inject的使用,不加@Named注解,需要配置与变量名一致即可。

    @Inject
    @Named("mongo")
    private Mongo mongo;

@Autowired

@Autowired有个属性为required,可以配置为false,如果配置为false之后,当没有找到相应bean的时候,系统不会抛错。

    @Autowired
    private MongoTemplate mongoTemplate;

@Resource

@Resource一般会指定一个name属性,如下

    @Resource(name = "testMapper")
    private TestMapper testMapper;
上一篇下一篇

猜你喜欢

热点阅读