Spring中注解实现原理
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中注解实现原理相关推荐
- Spring中注解大全
Spring中注解大全 @Controller 标识一个该类是Spring MVC controller 处理器,用来创建处理http请求的对象 @Controller public class Te ...
- spring系列-注解驱动原理及源码-AOP使用及源码解析
目录 一.用注解方式开启AOP 1.实例 2.AOP简单小结 二.AOP原理 1.@EnableAspectJAutoProxy溯源 2.AnnotationAwareAspectJAutoProxy ...
- spring系列-注解驱动原理及源码-声明式事务使用及原理解析
目录 一.环境准备 1.JdbcTemplate使用实例 2.事务添加 二.声明式事务源码分析 1.原理(与AOP非常相似) 一.环境准备 1.JdbcTemplate使用实例 (1)pom文件添加依 ...
- spring系列-注解驱动原理及源码-自动装配
目录 一.spring规范的bean自动注入 1.使用@Autowired自动注入 2.使用@Qualifier指定需要装配的组件 3.使用@Autowired装配null对象 4.使用@Primar ...
- spring系列-注解驱动原理及源码-bean生命周期
目录 一.Bean的初始化和销毁 1.@Bean指定初始化和销毁方法 2.通过实现InitializingBean和Disposabean来初始化和销毁bean 3.使用JSR250定义的@PostC ...
- spring系列-注解驱动原理及源码-bean组件注册
目录 一.环境初始化 1.环境准备 二.bean的手动注入 1.xml方式注入bean 2.使用@Configuration&@Bean方式注入bean 三.自动扫描注册组件及bean 1.使 ...
- Spring中注解大全和应用
点击上方△蓝字关注我们 带你征服编程和泡妞两座大山 @Controller @RestController: @Service @Autowired @RequestMapping @RequestP ...
- spring中注解的通俗解释
我们在没有用注解写spring配置文件的时候,会在spring配置文件中定义Dao层的bean,这样我们在service层中,写setDao方法,就可以直接通过接口调用Dao层,用了注解写法后,在配置 ...
- Spring中注解注入bean和配置文件注入bean
注解的方式确实比手动写xml文件注入要方便快捷很多,省去了很多不必要的时间去写xml文件 按以往要注入bean的时候,需要去配置一个xml,当然也可以直接扫描包体,用xml注入bean有以下方法: 1 ...
- 深入理解spring中的AOP原理——实现MethodInterceptor接口,自已动手写一个AOP
1.前言 AOP是面向切面编程,即"Aspect Oriented Programming"的缩写.面对切面,就是面向我们的关注面,不能让非关注面影响到我们的关注面.而现实中非关切 ...
最新文章
- python天气查询小程序加背景图_微信小程序开发背景图显示功能
- 微信小程序入门一: 简 介、文本、事件、样式
- Java并发编程笔记—基础知识—实用案例
- TwentyEleven暗色系主题实现透明
- 腾讯回应 QQ 被工信部通报;由微软老兵领导,Facebook 开发新操作系统;Node.js 13.4.0 发布 | 极客头条...
- c++多线程——基于锁和条件变量的前程安全队列
- python之判断一个值是不是可以被调用
- easypoi 大数据 百万_燃烧大数据 | 分析了2百万份成绩后发现,女跑者更稳?
- Vensim系统建模论文阅读-Information diffusion through social networks: The case of an online petition
- RemObjects Elements多用途软件开发
- 什么是 npm ?npm 下载安装使用
- java商城答辩_java网上商城系统毕业设计答辩.ppt
- 世界第4疯狂的科学家,在103岁生日那天去世了
- 如何将OGG文件转换成MP3?
- ionic3硬件检测、请求权限插件 Diagnostic 的用法
- android 图片裁剪库,(译)uCrop介绍 —— 我们自己的Android图片裁剪库
- iceberg-flink 十:flink任务后台关闭,并查找savepoint。
- 田忌赛马java lms_【044】:田忌赛马
- Python:dbus监控U盘插拔
- 广州融媒体峰会现场直播中,BirdDog Full NDI应用有哪些优点?难点?如何解决?
热门文章
- java后台生成内嵌logo的二维码图片以及添加文字
- 电信版的华为EC6108V9C刷机
- 嵌入式linux交叉开发环境,构建嵌入式Linux交叉开发环境
- 统计学计算机app,统计学计算器
- 常用服务器出厂默认管理口IP及账号密码
- spark python编程 林子雨_林子雨编著《Spark编程基础(Python版)》教材第5章的命令行和代码...
- idea git push 码云: Remote: [31mYou do not have permission to push to the repository via HTTPS
- 客户关系管理软件的作用是什么?
- Win10 安装 Ubuntu 使用 Linux 教程
- win10应用商店无法连接到服务器出错,解决win10应用商店无法登陆提示错误0x80070426的方法...