使用Spring AOP实现业务依赖解耦
Spring IOC用于解决对象依赖之间的解耦,而Spring AOP则用于解决业务依赖之间的解耦;
统一在一个地方定义【通用功能】,通过声明的方式定义这些通用的功能以何种【方式】【织入】到某些【特定应用】里去,并且【不需要修改】特定应用的代码;
-1通用功能:<aop:aspect>如日志、安全或事务,具体的方法动作称为Advice;
-2方式:<aop:before|after-returning|around>如方法调用、字段修改和抛出异常,Spring AOP仅支持方法调用(method execution join point);
-3织入:Weaving时期:编译期,类加载期和运行期,Spring AOP仅支持运行期植入;
-4 特定应用:<aop:pointcut>,匹配连接点,也就是指定aspect适配的目标方法;
-5不需要修改:动态为目标类创建代理对象,不需要修改业务代码本身;
AspectJ的功能比Spring AOP更加全面,如果需要可以在Spring中加载AspectJ的功能模块;使用Spring AOP除了常规Spring的jar包外还需要引入aspectjweaver-[xxx].jar;
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans">
<!-- Config for IOC -->
<context:component-scan base-package="com.active.leo.helloworld" />
<context:property-placeholder location="classpath:service.properties" />
<import resource="webmvc-config.xml" /> <!-- Config for AOP -->
<aop:aspectj-autoproxy />
<bean id="audience" class="com.active.leo.helloworld.Audience" /> <aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="performance"
expression="execution(* com.active.leo.helloorld.Performer.perform(..))" /> <aop:before pointcut-ref="performance" method="takeSeats" />
<aop:before pointcut-ref="performance" method="turnOffCellPhones" />
<aop:after-returning pointcut-ref="performance" method="applaud" />
<aop:after-throwing pointcut-ref="performance" method="demandRefund" />
</aop:aspect>
</aop:config>
</bean>
</beans>
-1 <aop:aspct>表示定义一个切面,并且与名为audience的切面实现类关联;
-2 <aop:pointcut>表示定义一个名为performance的切点,并与需要进行AOP的目标业务方法绑定;execution的目标方法匹配的pattern:
execution([modifiers?] [return-type] [declaring –type?] [func-name]([param-name]) [throw-exp?] )
其他的还有within(表示被某个注解标注的所有类), this, target和args;
-3 <aop:before>表示调用目标业务perform方法之前触发AOP,perform方法一定会执行;
-4 <aop:after-returning>表示调用perform方法触发正常结束之后触发AOP;
-5 <aop:after-throwing>表示调用perform方法抛出异常后触发AOP;
-6 <aop:around>合并before和after-returning,PreceedingJoinPoint.proceed()为目标动作;可以控制执行流程,可根据情况决定是否执行perform方法;
如果目标动作有参数,可以借助arg/arg-names在切面方法中获取;
通过注解实现Spring AOP
首先要创建一个用于config的Java Bean,
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {}
然后通过@Aspect,@Pointcut,@Before,@AfterReturning,@Around等实现;所有使用AspectJ标注的前提条件是JavaBean可以被ClassLoader发现,所以需要额外添加@Component用于被IOC容器发现;被申明为Aspect的JavaBean不能用于其他Aspect的auto-proxying;
一般的Aspect的生命周期都是singleton,当然也可以设置成perflow, perthis, pertypewithin, pertarget的不同周期;实现org.springFramework.core.Ordered接口,重写getOrder()方法可以控制当前advice在目标方法周边的执行有限顺序;
public class App {
public void func1() {}
public void func2() {}
}
@Aspect
public class SpringAopAspectDemo implements Ordered {
@Pointcut("execution(* com.test.spring.aspectj.App.func1(..))")
public void pointcut4Func1() {}
@Pointcut("execution(* com.test.spring.aspectj.App.func2(..))")
public void pointcut4Func2() {}
@Around("pointcut4Func1()")
public Object doDevice(ProceedingJoinPoint pjp) throws Throwable {
//something needs to be done in aspect.
}
}
使用@Interface实现自定义注解
通过@Interface自定义注解,并结合spring AOP可以实现针对request的权限校验,
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionRequired {
boolean isReqiureAuth default false;
boolean isRequireAuzh default false;
} >>>>>>>>>>>>> @Pointcut("execution(* com.ychen.application.*.*(..)) && "
+ "@annotation(requiredPermission)")
public void pointController(RequiredPermission requiredPermission) {
// nothing
} @Around("pointController(requiredPermission)")
public Object applySecurityCheck(ProceedingJoinPoint point,
RequiredPermission requiredPermission) throws Throwable {
// auth check
}
Spring AOP使用JDK Dynamic Proxy和CGLIB对目标类进行代理:
#1 JDK Dynamic Proxy方式使用Java Reflection技术,实现InvocationHandler接口,因此要求目标类有一个Interface,并且目标方法需要在此Interface中申明,动态创建一个实现了Interface的类并在该类中调用目标类的方法;
public class PerformanceMonitorProxy implements InvocationHandler {
private Object target;
public ServiceWithPerformanceMonitorProxy(Object target) {
this.target = target;
}
public static Object newProxyInstance(Object target) {
Class clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),
new ServiceWithPerformanceMonitorProxy(target));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//do something before target function invocation
PerformanceMonitor.begin(method.getName());
Object result = method.invoke(target, args);
//do something after target function invocation
PerformanceMonitor.end(method.getName());
return result;
}
}
#2 CGLIB使用字节码技术,实现MethodInterceptor接口,动态生成一个目标类的子类,通过over-write去覆盖目标方法的执行,并在子类方法中调用目标方法的前后进行AOP;
public class CGlibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
// 代理执行时会回调此this持有的intercept方法,以实现代码织入
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object target, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
PerformanceMonitor.begin(method.getName());
Object result = methodProxy.invokeSuper(target, args);
// 下面这样是无法执行原有方法的,因为这里的target并不是原有类的实例,而是代理类的实例
// target :
// com.dianping.aop.AdminServiceImpl$$EnhancerByCGLIB$$225da297@16dd5a9d
// Object result = method.invoke(target, args);
PerformanceMonitor.end(method.getName());
return result;
}
}
Spring一般首选JDK Dynamic Proxy进行代理,如果遇到没有实现Interface的情况则使用CGLIB,当然可以通过下属设置强制使用CGLIB;
<aop:config proxy-target-class="true">
<!-- other beans defined here... -->
</aop:config>
使用Spring AOP实现业务依赖解耦的更多相关文章
- 转:spring aop 拦截业务方法,实现权限控制
难点:aop类是普通的java类,session是无法注入的,那么在有状态的系统中如何获取用户相关信息呢,session是必经之路啊,获取session就变的很重要.思索很久没有办法,后来在网上看到了 ...
- spring aop 拦截业务方法,实现权限控制
难点:aop类是普通的java类,session是无法注入的,那么在有状态的系统中如何获取用户相关信息呢,session是必经之路啊,获取session就变的很重要.思索很久没有办法,后来在网上看到了 ...
- Spring AOP基于注解的“零配置”方式实现
为了在Spring中启动@AspectJ支持,需要在类加载路径下新增两个AspectJ库:aspectjweaver.jar和aspectjrt.jar.除此之外,Spring AOP还需要依赖一个a ...
- 用心整理 | Spring AOP 干货文章,图文并茂,附带 AOP 示例 ~
Spring AOP 是 Java 面试的必考点,我们需要了解 AOP 的基本概念及原理.那么 Spring AOP 到底是啥,为什么面试官这么喜欢问它呢?本文先介绍 AOP 的基本概念,然后根据 A ...
- Spring AOP中使用@Aspect注解 面向切面实现日志横切功能详解
引言: AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一 ...
- spring Aop 注解
个人理解: spring Aop 是什么:面向切面编程,类似于自定义拦截操作,支持拦截之前操作@Before,拦截之后操作@After,拦截环绕操作@Around. 什么情况下使用spring Aop ...
- Spring aop+自定义注解统一记录用户行为日志
写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...
- Spring AOP源码分析(二):AOP的三种配置方式与内部解析实现
AOP配置 在应用代码中,可以通过在spring的XML配置文件applicationContext.xml或者基于注解方式来配置AOP.AOP配置的核心元素为:pointcut,advisor,as ...
- 曹工说Spring Boot源码(22)-- 你说我Spring Aop依赖AspectJ,我依赖它什么了
写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...
随机推荐
- 详解Codis安装与部署
Codis github上的介绍安装,里面很全,而且也有中/英文的,只不过按照github的步骤安装,会有一些坑,所以有了这么一篇文章. 在上一篇文章<Redis实用监控工具一览>中,介绍 ...
- 如何在普通 UIViewController 中使用 UITableView
本系列文章 <Swift on iOS 学习笔记> 将以不定长度.不定内容.不定形式的方式对外发布,主要记录一些 “可重用” 的知识,感谢你的阅读. 在继承自 UIViewControll ...
- Python 实现简单的登录注册界面
Python 实现简单的登录注册界面 注意:编写代码之前需要导入很重要的包 import tkinter as tk import pickle from tkinter import message ...
- assembly x86(nasm)画三角形等图形的实现(升级版)
https://www.cnblogs.com/lanclot-/p/10962702.html接上一篇 本来就有放弃的想法,可是有不愿退而求次, 然后大神室友写了一个集海伦公式计算三角形面积, 三点 ...
- 全球首款iOS模拟器出炉!在违法的边缘疯狂试探
对于许多智能手机用户,特别是手游玩家来说,在手机屏幕的方寸之间进行操作显然并非特别方便,而且在多年之前,由于手机配置不足,也导致了用PC来玩手游的需求不断涌现.彼时,BlueStacks及夜神等一众A ...
- 字符串匹配,KMP算法
KMP的详解见:https://segmentfault.com/a/1190000008575379 主要难点在于Next数组的理解,KMP是不需要回溯的匹配算法. #include<iost ...
- 栈 && 教授的测试
卡特兰数:https://blog.csdn.net/wu_tongtong/article/details/78161211 https://www.luogu.org/problemnew/sho ...
- [译]Understanding ECMAScript6 基本知识
基本知识 ECMAScript 6在ECMAScript 5之上做了大量的改变.一些改变很大,比如添加新的类型或者语法,而其它的非常小,提供了语言之上的渐进改进.这个章节包含了那些渐进改进,它们可能不 ...
- 图像分类丨浅析轻量级网络「SqueezeNet、MobileNet、ShuffleNet」
前言 深度卷积网络除了准确度,计算复杂度也是考虑的重要指标.本文列出了近年主流的轻量级网络,简单地阐述了它们的思想.由于本人水平有限,对这部分的理解还不够深入,还需要继续学习和完善. 最后我参考部分列 ...
- asp。Net 页面传值
00.引言 Web页面是无状态的, 服务器对每一次请求都认为来自不同用户,因此,变量的状态在连续对同一页面的多次请求之间或在页面跳转时不会被保留.在用ASP.NET 设计开发一个Web系统时, 遇到一 ...