一、AOP的概念
AOP(Aspect Oriented Programming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。使用AOP技术,可以将一些与系统相关的业务逻辑功能模块,提取出来,独立实现,然后通过切面切入进系统。从而避免了在核心业务逻辑的代码中混入很多的系统相关的逻辑——比如事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等等。
二、AOP的实现原理是什么
AOP主要是通过代理模式来实现,主要分为JDK动态代理和CGLib动态代理。下面我们的详细了解一下这两种代理模式的原理。
1、JDK动态代理
JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。
nvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
下面是JDK动态代理的类图:
根据上面的类图 ,下面我们通过一个查看员工工资系统的示例代码了解JDK的动态代理。在工资系统中业务逻辑包括。查看员工工资、系统安全、操作权限和日志管理。其中主要核心业务逻辑是查看员工的工资。
1. 查看员工工资
//定义的SalaryManager接口
public interface SalaryManager {
public void showSalary();
}
//接口SalaryManager的具体实现类
public class SalaryManagerImpl implements SalaryManager{
public void showSalary() {
System.out.println("show salary");
}
}
2. 系统安全
public class Security {
public void security(){
System.out.println("security");
}
}
3.操作权限
public class Privilege {
private String access;
public String getAccess() {
return access;
}
public void setAccess(String access) {
this.access = access;
}
}
4.日志管理
public class Logger {
public void logging(){
System.out.println("logging");
}
}
5.实现InvocationHandler接口,将所有的业务逻辑组合在一起
public class MyInterceptor implements InvocationHandler{
private Object target;
private Logger logger;
private Security security;
private Privilege privilege;
public MyInterceptor(Object target, Logger logger, Security security,
Privilege privilege) {
super();
this.target = target;
this.logger = logger;
this.security = security;
this.privilege = privilege;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/**
* 1、启动日志
* 2、启动安全性的类
* 3、验证权限
* 调用目标对象的目标方法
*/
this.logger.logging();
this.security.security();
if("admin".equals(this.privilege.getAccess())){
method.invoke(target);//动态调用目标方法
}else{
System.out.println("没有权限查看工资");
}
return null;
}
}
6.使用Proxy接口 ,生成目标类的代理对象
public class SalaryTest {
@Test
public void testSalary(){
Object target = new SalaryManagerImpl();
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
privilege.setAccess("asfd");
MyInterceptor interceptor = new MyInterceptor(target, logger, security, privilege);
SalaryManager proxy = (SalaryManager)Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(), interceptor);
proxy.showSalary();
}
}
2、CGLib动态代理
CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。
(备注:其代码演示就不在此赘述)
3、JDK和CGLib动态代理区别
JDK和CGLib动态代理区别主要体现在以下两点
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,生成代理类是目标类的子类
备注:在Spring中对于AOP代理类的生成原则是:
如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类
三、在Spring中AOP的配置方式
首先,我们结合上述查看员工工资的系统实例代码来看一下,AOP中的一些重要概念
- 切面(Aspect):就是除了核心关注点之外所有操作。例如 : Security ,Privilege 类就是切面。“切面”在ApplicationContext中来配置。
- 连接点(Joinpoint) :目标类的中方法 。例如SalaryManager中的 showSalary()方法。
- 通知(Advice) :“切面”对于某个“连接点”所产生的动作,其实,就是切面中方法。例如:Security 类中security()方法。
- 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。就相当于条件判断语句。例如:在上述testSalary 中 if(“admin”.equals(this.privilege.getAccess()))而在 都由切入点表达式execution(* com.spring.service..(..))来决定
Spring中AOP实现在XML中的配置方式示例:
<tx:advice transaction-manager="transationManager" id="tx">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.ywendeng.ecs.service.*.*(..))" id="perfrom"/>
<aop:advisor advice-ref="tx" pointcut-ref="perfrom"/>
</aop:config>