spring的启动过程02.1-aop命名空间解读
来源:互联网 发布:b2b群发信息软件 编辑:程序博客网 时间:2024/05/21 20:30
概述:
aop是spring框架的核心思想之一,系统开发中会采用aop的方式进行业务逻辑的动态植入,如登录授权、日志统计等。该篇文章首先会讲解aop的基础概念,然后讲解spring通过命名空间方式如何实现aop的功能。
- AOP基础:
AOP核心概念
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)
对连接点进行拦截的定义
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
Spring对AOP的支持
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
1、定义普通业务组件
2、定义切入点,一个切入点可能横切多个业务组件
3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。
Spring强制使用CGLIB代理事务
当需要使用CGLIB代理和@AspectJ自动代理支持,请按照如下的方式设置 |aop:aspectj-autoproxy| 的 proxy-target-class 属性:
<aop:aspectj-autoproxyproxy-target-class="true"expose-proxy="true"/>
Spring是依靠什么来判断采用哪种代理策略来生成AOP代理呢?以下代码就是Spring的判断逻辑
//org.springframework.aop.framework.DefaultAopProxyFactory
//参数AdvisedSupport 是Spring AOP配置相关类
public AopProxy createAopProxy(AdvisedSupport advisedSupport)
throws AopConfigException {
//在此判断使用JDK动态代理还是CGLIB代理
if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass()
|| hasNoUserSuppliedProxyInterfaces(advisedSupport)) {
if (!cglibAvailable) {
throw new AopConfigException(
"Cannot proxy target class because CGLIB2 is not available. "
+ "Add CGLIB to the class path or specify proxy interfaces.");
}
return CglibProxyFactory.createCglibProxy(advisedSupport);
} else {
return new JdkDynamicAopProxy(advisedSupport);
}
}
(标准接口包)
aspectjweaverASM.jar(java字节码操纵框架)
cglib.jar加载目标类的字节码,植入需要增强处理
然后动态生成目标类的子类
生成的类与目标类属于继承关系JDK 无采用JDK自带动态代理方式,获取目标类的
接口,动态生成接口的实现类
生产的类与目标类属于接口的不同实现类
不能进行强制转换操作
@AspectJ的详细用法
一些常见的切入点的例子
execution(public * * (. .)) 任意公共方法被执行时,执行切入点函数。
execution( * set* (. .)) 任何以一个“set”开始的方法被执行时,执行切入点函数。
execution( * com.demo.service.AccountService.* (. .)) 当接口AccountService 中的任意方法被执行时,执行切入点函数。
execution( * com.demo.service.*.* (. .)) 当service 包中的任意方法被执行时,执行切入点函数。 within(com.demo.service.*) 在service 包里的任意连接点。 within(com.demo.service. .*) 在service 包或子包的任意连接点。
this(com.demo.service.AccountService) 实现了AccountService 接口的代理对象的任意连接点。
target(com.demo.service.AccountService) 实现了AccountService 接口的目标对象的任意连接点。
args(Java.io.Serializable) 任何一个只接受一个参数,且在运行时传入参数实现了 Serializable 接口的连接点
增强的方式:
@Before:方法前执行
@AfterReturning:运行方法后执行
@AfterThrowing:Throw后执行
@After:无论方法以何种方式结束,都会执行(类似于finally)
@Around:环绕执行
- spring如何实现AOP功能
看下aop命名空间的定义:
spring.handlers文件中
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
spring.schemas文件中
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.2.xsd
看下AopNamespaceHandler类内容
public class AopNamespaceHandler extends NamespaceHandlerSupport {/** * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}' * and '{@code scoped-proxy}' tags. */@Overridepublic void init() {// In 2.0 XSD as well as in 2.1 XSD.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());// Only in 2.0 XSD: moved to context namespace as of 2.1registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());}}看下AspectJAutoProxyBeanDefinitionParser类:
@Overridepublic BeanDefinition parse(Element element, ParserContext parserContext) {AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);extendBeanDefinition(element, parserContext);return null;}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, Object source) {if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);if (!cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());int requiredPriority = findPriorityForClass(cls);if (currentPriority < requiredPriority) {apcDefinition.setBeanClassName(cls.getName());}}return null;}// 创建一个名称为org.springframework.aop.config.internalAutoProxyCreator的bean定义RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);beanDefinition.setSource(source);// 并设置优先级为最高beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);// 注册到上下文registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);return beanDefinition;}创建好bean定义后设置proxy-target-class、expose-proxy两个参数值
proxy-target-class:强制spring内部使用CGLIB生成代理对象。
expose-proxy:当前代理是否为可暴露状态,值为true则为可访问。
可以参考:http://blog.csdn.net/derrantcm/article/details/46284811
总结:
主要介绍spring如何用注解方式具有aop功能,后续会讲解AnnotationAwareAspectJAutoProxyCreator类的具体功能。
1 0
- spring的启动过程02.1-aop命名空间解读
- spring的启动过程02.2-tx命名空间解读
- 基于tx/aop命名空间的spring声明式事务管理
- spring的aop解读
- spring命名空间解析以及aop命名空间背后干的事
- Spring中基于aop命名空间的AOP 二(声明一个切面、切入点和通知)
- 使用Spring AOP与Annotation所需的jar包以及命名空间操作
- 深入解读Spring Framework IoC容器(第四弹:p命名空间和c命名空间)
- spring aop实现的过程
- Spring4.3.x 浅析xml配置的解析过程(9)——解析aop命名空间之config标签
- 详细解读php的命名空间(一)
- spring命名空间的配置方式
- Spring xsi本地命名空间的思考
- Spring的内部bean与空间命名
- 查看spring命名空间的版本号
- spring 配置文件 常使用的命名空间
- spring配置文件 --可恶的命名空间
- spring的xml配置文件中命名空间
- 7个你可能不认识的CSS单位:rem vh vw vmin vmax ex ch
- net.sf.json.JSONObject 为 null 的判断
- 线性表、栈、队列和优先队列
- 带有本地数据排序和筛选的RecyclerView Adapter
- 继承中的同名成员变量处理方法
- spring的启动过程02.1-aop命名空间解读
- googlesamples之easypermissions使用
- 信源采集数据后如何存储,如何表示?
- java中的POJO是什么意思?
- 8 对list进行切片(Slice)
- nodejs中exports与module.exports的区别详细介绍
- 弹道解算(一)
- 电脑开机提示lsic memory usable 0x176
- 不同电脑上提交 gerrit