Spring AOP(面向切面编程)
根据个人理解,AOP就是对指定的目标方法绑定各种拦截程序
如:A框架代码是所有程序必须的 , B程序想运行,运行前A框架初始化代码必须先运行 , B程序运行完后还需要执行A框架销毁代码;
如果有100个程序呢 , 那每个程序都需要写入A 框架的初始化和销毁程序 , 这显然不明智
AOP出现就解决了这个问题
如下图所示,
切面: 对目标类进行拦截后运行的程序
目标类的目标方法 : 切入点, 被切面拦截的程序
代理拦截器 : 将所有的切面和目标类引入 (所以的东西代理进来),通过构造器赋值,填充代理方法 ,
最后目标类可以通过代理拦截器产生具有切面拦截的代理对象!!!
实现代理拦截器
JDK 代理 或者CGLIB代理 动态代理实现代理拦截器
一、原理区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
4、jdk代理 : 代理对象和目标对象实现了共同的接口
cglib代理 : 代理对象是目标对象的子类
JDK代理 - 实现动态代理拦截器
目标类
public class SalaryMainImp implements SalaryMain {
@Override
public void showSalary() {
System.out.println("查看工资");
}
}
切面拦截类
//切面
public class Logger {
public void logger(){
System.out.println("启动日志~~~~~");
}
}
***************************************************
//切面
public class Security {
public void security() {
System.out.println("启动安全框架~~~~~");
}
}
代理拦截器
/* 代理拦截器 实现 InvocationHandler
* 将所有的切面和目标类引入 (所以的东西代理进来)
* 通过构造器赋值
* 填充invoke方法
*
* */
public class SalaryInterceptor implements InvocationHandler {
private Object target; //目标类
private Logger logger; //日志类切面
private Security security; //安全框架类切面
public SalaryInterceptor(Object target, Logger logger, Security security, Privilege privilege) {
this.target = target;
this.logger = logger;
this.security = security;
this.privilege = privilege;
}
@Override
//整合所需切面和目标类的程序!!!
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.logger.logger(); //启动日志
this.security.security(); //启动安全框架
method.invoke(this.target, args); //代理目标类的方法
return null;
}
}
*************************************************************************************
*************************************************************************************
@Test
Logger logger = new Logger(); //创建日志对象
Security security = new Security(); //创建安全框架对象
Object target = new SalaryMainImp(); //目标类
//创建代理拦截器
SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, logger, security);
//传入目标类装载器,目标类接口,指定拦截器 ,生成代理对象 ,JDK代理只能用目标类接口生产代理对象!所以目标类必须是继承一个接口!
SalaryMain salaryMain = (SalaryMain) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), salaryInterceptor);
salaryMain.showSalary();
总结: 此为JDK动态代理,由于目标类类型为Object ,所以可以传入任何目标类都能生成代理接口
CGLIB代理 - 实现动态代理拦截器
与JDK代理类似,如果切面拦截过多,可以使用集合构造
目标类
public class SalaryMainImp implements SalaryMain {
@Override
public void showSalary() {
System.out.println("查看工资");
}
}
切面拦截类
//实现 拦截器 切面总接口
public class Logger implements Interceptor {
@Override
public void interceptor() {
System.out.println("启动日志~~~~~");
}
}
**********************************************
//实现 拦截器 切面总接口
public class Security implements Interceptor {
@Override
public void interceptor() {
System.out.println("启动安全框架~~~~~");
}
}
代理拦截器
public class SalaryInterceptor implements MethodInterceptor {
private Object target; //目标类
private List<Interceptor> interceptorList; //切面集合
public SalaryInterceptor(Object target, List<Interceptor> interceptorList) {
this.target = target;
this.interceptorList = interceptorList;
}
/*
*产生代理对象
* @return
* */
public Object createProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass()); //设置代理对象的父类
enhancer.setCallback(this); //设置拦截器
return enhancer.create();
}
//整合所需切面和目标类
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//遍历切面集合,调用每个切面的拦截方法
for (Interceptor interceptor : interceptorList) {
interceptor.interceptor();
}
method.invoke(this.target, objects); //代理目标类的方法
return null;
}
}
*************************************************************************
*************************************************************************
@Test
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
Object target = new SalaryMainImp(); //目标类
//将所需切面存入集合中
List<Interceptor> interceptors = new ArrayList<>();
interceptors.add(logger);
interceptors.add(security);
interceptors.add(privilege);
//传入 目标类, 切面拦截集合 ,返回代理拦截器
SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, interceptors);
//通过代理拦截器,创建代理对象
SalaryMainImp salaryMain = (SalaryMainImp) salaryInterceptor.createProxy();
// Enhancer enhancer=new Enhancer();
// enhancer.setSuperclass(target.getClass());
// enhancer.setCallback(salaryInterceptor);
// SalaryMain salaryMain=(SalaryMain)enhancer.create(); 这个步骤可存到代理拦截器中
salaryMain.showSalary();
/*
在调用 show () 之前,需要启动某些程序,框架
这时就可以用该思想,讲切面 和目标类 都进行代理 整合到一起
* */
}
总结 : AOP简单来说就是代码的增强, 给指定的程序增加功能!!! ,通过代码拦截器对指定类的方法增加功能!