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;
网友评论