Spring中注解实现原理

Spring中有哪些注解

Spring中的注解主要分为两类:

  • 类级别的注解:如@Component、@Repository、@Controller、@Service以及JavaEE6的@ManagedBean和@Named注解,都是添加在类上面的类级别注解。

  • 类内部的注解:如@Autowire、@Value、@Resource以及EJB和WebService相关的注解等,都是添加在类内部的字段或者方法上的类内部注解。

具体的来说又有以下几种类型的注解方式:

1.声明bean的注解

@Component 组件,通用的注解方式

@Service 在业务逻辑层使用(service层)

@Repository 在数据访问层使用(dao层)

@Controller 在表现层使用,控制器的声明(C)

2.注入bean的注解

@Autowired:由Spring提供

@Inject:由JSR-330提供

@Resource:由JSR-250提供

都可以注解在set方法和属性上,推荐注解在属性上(一目了然,少写代码)。

3.java配置类相关注解

@Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上)

@Bean 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上)

@Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上)

@ComponentScan 用于对Component进行扫描,相当于xml中的(类上)

@WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解

4.切面(AOP)相关注解

Spring支持AspectJ的注解式切面编程。

@Aspect 声明一个切面(类上)

使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。

@After 在方法执行之后执行(方法上) @Before 在方法执行之前执行(方法上) @Around 在方法执行之前与之后执行(方法上)

@PointCut 声明切点

在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)

5.@Bean的属性支持

@Scope 设置Spring容器如何新建Bean实例(方法上,得有@Bean)

其设置类型包括:

· Singleton (单例,一个Spring容器中只有一个bean实例,默认模式),

· Protetype (每次调用新建一个bean),

· Request (web项目中,给每个http request新建一个bean),

· Session (web项目中,给每个http session新建一个bean),

· GlobalSession(给每一个 global http session新建一个Bean实例)

@StepScope 在Spring Batch中还有涉及

@PostConstruct 由JSR-250提供,在构造函数执行完之后执行,等价于xml配置文件中bean的initMethod

@PreDestory 由JSR-250提供,在Bean销毁之前执行,等价于xml配置文件中bean的destroyMethod

Spring中的注解的实现原理

Spring中注解的实现原理需要分为类级别注解和类内部级别注解分开讨论。

(1)类级别的注解

Spring容器根据注解的过滤规则扫描读取注解Bean定义类,并将其注册到Spring IoC容器中。

下面拿spring的controller来当做示例:

​ Controller类使用继承@Component注解的方法,将其以单例的形式放入spring容器,如果仔细看的话会发现每个注解里面都有一个默认的value()方法,它的作用是为当前的注解声明一个名字,一般默认为类名,然后spring会通过配置文件中的context:component-scan的配置,进行如下操作:

1、使用asm技术扫描.class文件,并将包含@Component及元注解为@Component的注解@Controller、@Service、@Repository或者其他自定义的的bean注册到beanFactory中,

2、然后spring在注册处理器

3、实例化处理器,然后将其放到beanPostFactory中,然后我们就可以在类中进行使用了。

4、创建bean时,会自动调用相应的处理器进行处理。

(2)类内部级别的注解

注解 Autowired 的简单使用

既然要研究多个 Bean 之间的依赖注入,那么就先创建两个 Bean,分别为 ServiceA 和 ServiceB。

ServiceA 代码如下:

public class ServiceA {public String getServiceName() {return serviceName;}public void setServiceName(String serviceName) {this.serviceName = serviceName;}private String serviceName;public void sayHello() {System.out.println("serviceA sayHello " + serviceName);}
} 

ServiceB,代码如下:

import org.springframework.beans.factory.annotation.Autowired;public class ServiceB {@Autowiredprivate ServiceA serviceA;public ServiceA getServiceA() {return serviceA;}public void setServiceA(ServiceA serviceA) {this.serviceA = serviceA;}public void sayHello() {serviceA.sayHello();}
}

如上代码可知 ServiceB 内部使用注解 @Autowired 注入了 ServiceA 的实例。

然后使用下面 bean-test.xml 文件配置两个 Bean 的实例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="serviceA" class="com.jiaduo.test.ServiceA"></bean><bean id="serviceB" class="com.jiaduo.test.ServiceB"></bean></beans>

最后测试类代码如下:

public class TestAuowired {public static void main(String[] arg) {ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext("bean-test.xml");cpxa.getBean("serviceB", ServiceB.class).sayHello();}
}

运行测试代码,我们期望输出 serviceA sayHello null,但是结果却是如下:

log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" java.lang.NullPointerExceptionat com.jiaduo.test.ServiceB.sayHello(ServiceB.java:11)at com.jiaduo.test.TestAuowired.main(TestAuowired.java:14)

从异常结果知道,ServiceB 里面的 serviceA 对象为 null,也就是 XML 里面配置的 serviceA 对象并没有被注入到 ServiceB 实例内。其实要想使用 @Autowired 需要显示的注册对应的注解的处理器到 Spring 容器,具体是需要在 bean-test.xml 里面添加 ``,添加后在运行代码就会输出 serviceA sayHello null 了。

需要注意的是 @Autowired 除了可以标注在变量上,还可以标注在变量对应的 set 访问器上,比如下面代码1和代码2效果是一样。

代码1:

@Autowired
public void setServiceA(ServiceA serviceA) {this.serviceA = serviceA;
}

代码2:

@Autowired
private ServiceA serviceA;

AutowiredAnnotationBeanPostProcessor 原理剖析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5jn7llVS-1589088268941)(C:\Users\18221\AppData\Roaming\Typora\typora-user-images\image-20200510131454115.png)]

AutowiredAnnotationBeanPostProcessor 直接或者间接实现了 Spring 框架的好多扩展接口:

  • 实现了 BeanFactoryAware 接口,可以让 AutowiredAnnotationBeanPostProcessor 获取到当前 Spring 应用程序上下文管理的 BeanFactory,从而可以获取到 BeanFactory 里面所有的 Bean。
  • 实现了 MergedBeanDefinitionPostProcessor 接口,可以让 AutowiredAnnotationBeanPostProcessor 对 BeanFactory 里面的 Bean 在被实例化前对 Bean 定义进行修改。
  • 继承了 InstantiationAwareBeanPostProcessorAdapter,可以让 AutowiredAnnotationBeanPostProcessor 在 Bean 实例化后执行属性设置。

Spring 框架会在创建 AutowiredAnnotationBeanPostProcessor 实例过程中调用 setBeanFactory 方法注入 Spring 应用程序上下文管理的 BeanFactory 到 AutowiredAnnotationBeanPostProcessor 中,所以 AutowiredAnnotationBeanPostProcessor 就可以操作 BeanFactory 里面的所有的 Bean 了。

在 Spring 中每个 Bean 实例化前,Spring 框架都会调用 AutowiredAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class beanType, String beanName) 方法,用来对当前 Bean 的定义(beanDefinition)进行修改,这里主要通过 findAutowiringMetadata 方法找到当前 Bean 中标注 @Autowired 注解的属性变量和方法。

Spring实现@Autowire解析和注入的核心的类是通过AutowiredAnnotationBeanPostProcessor来实现的。

我们可以通过其方法列表看出,其中对字段的注入,对属性的注入,还有选择相应的构造方法来注入。

1,从构造方法的缓存中查询其构造方法

2,若缓存中不存在,则根据反射获取所有构造方法

3,遍历所有构造方法,查询构造器是否含有@Autowired属性

4,判断Autowired注解中指定了required属性 (required属性就是判断是否强依依赖)若存在required就使用默认构造方法。

5,返回指定的构造方法

注入的时候则是通过inject方法来实现。

Spring对注解的支持主要都是通过反射来获取相应的注解

使用@Autowired注解来自动装配指定的bean。

在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法

注:@Autowired和@Resource之间的区别

(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

bean装配给@Autowired指定的数据;

如果查询的结果不止一个,那么@Autowired会根据名称来查找;

如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

@Autowired可用于:构造函数、成员变量、Setter方法

注:@Autowired和@Resource之间的区别

(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。

(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。

参考原文链接:https://www.cnblogs.com/kaleidoscope/p/9766720.html

Spring中注解实现原理相关推荐

  1. Spring中注解大全

    Spring中注解大全 @Controller 标识一个该类是Spring MVC controller 处理器,用来创建处理http请求的对象 @Controller public class Te ...

  2. spring系列-注解驱动原理及源码-AOP使用及源码解析

    目录 一.用注解方式开启AOP 1.实例 2.AOP简单小结 二.AOP原理 1.@EnableAspectJAutoProxy溯源 2.AnnotationAwareAspectJAutoProxy ...

  3. spring系列-注解驱动原理及源码-声明式事务使用及原理解析

    目录 一.环境准备 1.JdbcTemplate使用实例 2.事务添加 二.声明式事务源码分析 1.原理(与AOP非常相似) 一.环境准备 1.JdbcTemplate使用实例 (1)pom文件添加依 ...

  4. spring系列-注解驱动原理及源码-自动装配

    目录 一.spring规范的bean自动注入 1.使用@Autowired自动注入 2.使用@Qualifier指定需要装配的组件 3.使用@Autowired装配null对象 4.使用@Primar ...

  5. spring系列-注解驱动原理及源码-bean生命周期

    目录 一.Bean的初始化和销毁 1.@Bean指定初始化和销毁方法 2.通过实现InitializingBean和Disposabean来初始化和销毁bean 3.使用JSR250定义的@PostC ...

  6. spring系列-注解驱动原理及源码-bean组件注册

    目录 一.环境初始化 1.环境准备 二.bean的手动注入 1.xml方式注入bean 2.使用@Configuration&@Bean方式注入bean 三.自动扫描注册组件及bean 1.使 ...

  7. Spring中注解大全和应用

    点击上方△蓝字关注我们 带你征服编程和泡妞两座大山 @Controller @RestController: @Service @Autowired @RequestMapping @RequestP ...

  8. spring中注解的通俗解释

    我们在没有用注解写spring配置文件的时候,会在spring配置文件中定义Dao层的bean,这样我们在service层中,写setDao方法,就可以直接通过接口调用Dao层,用了注解写法后,在配置 ...

  9. Spring中注解注入bean和配置文件注入bean

    注解的方式确实比手动写xml文件注入要方便快捷很多,省去了很多不必要的时间去写xml文件 按以往要注入bean的时候,需要去配置一个xml,当然也可以直接扫描包体,用xml注入bean有以下方法: 1 ...

  10. 深入理解spring中的AOP原理——实现MethodInterceptor接口,自已动手写一个AOP

    1.前言 AOP是面向切面编程,即"Aspect Oriented Programming"的缩写.面对切面,就是面向我们的关注面,不能让非关注面影响到我们的关注面.而现实中非关切 ...

最新文章

  1. python天气查询小程序加背景图_微信小程序开发背景图显示功能
  2. 微信小程序入门一: 简 介、文本、事件、样式
  3. Java并发编程笔记—基础知识—实用案例
  4. TwentyEleven暗色系主题实现透明
  5. 腾讯回应 QQ 被工信部通报;由微软老兵领导,Facebook 开发新操作系统;Node.js 13.4.0 发布 | 极客头条...
  6. c++多线程——基于锁和条件变量的前程安全队列
  7. python之判断一个值是不是可以被调用
  8. easypoi 大数据 百万_燃烧大数据 | 分析了2百万份成绩后发现,女跑者更稳?
  9. Vensim系统建模论文阅读-Information diffusion through social networks: The case of an online petition
  10. RemObjects Elements多用途软件开发
  11. 什么是 npm ?npm 下载安装使用
  12. java商城答辩_java网上商城系统毕业设计答辩.ppt
  13. 世界第4疯狂的科学家,在103岁生日那天去世了
  14. 如何将OGG文件转换成MP3?
  15. ionic3硬件检测、请求权限插件 Diagnostic 的用法
  16. android 图片裁剪库,(译)uCrop介绍 —— 我们自己的Android图片裁剪库
  17. iceberg-flink 十:flink任务后台关闭,并查找savepoint。
  18. 田忌赛马java lms_【044】:田忌赛马
  19. Python:dbus监控U盘插拔
  20. 广州融媒体峰会现场直播中,BirdDog Full NDI应用有哪些优点?难点?如何解决?

热门文章

  1. java后台生成内嵌logo的二维码图片以及添加文字
  2. 电信版的华为EC6108V9C刷机
  3. 嵌入式linux交叉开发环境,构建嵌入式Linux交叉开发环境
  4. 统计学计算机app,统计学计算器
  5. 常用服务器出厂默认管理口IP及账号密码
  6. spark python编程 林子雨_林子雨编著《Spark编程基础(Python版)》教材第5章的命令行和代码...
  7. idea git push 码云: Remote: [31mYou do not have permission to push to the repository via HTTPS
  8. 客户关系管理软件的作用是什么?
  9. Win10 安装 Ubuntu 使用 Linux 教程
  10. win10应用商店无法连接到服务器出错,解决win10应用商店无法登陆提示错误0x80070426的方法...