一、AOP简介
1、概念
- Aop(Aspect Oriented Programming),面向切面编程,这是对面向对象思想的一种补充。
- 面向切面编程,就是在程序运行时,不改变程序源码的情况下,动态的增强方法的功能,常见的使用场景非常多
日志
事务
数据库操作
….
这些操作中,无一例外,都有很多模板化的代码,而解决模板化代码,消除臃肿就是 Aop 的强项。
2、AOP原理
简介: 动态代理,在 Aop 实际上集基于 Java 动态代理来实现的。Java 中的动态代理有两种实现方式:
- cglib:全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,对类字节码进行代理
- jdk动态代理: == 前提是对象必须要有实现接口,使用java.lang.reflection.Proxy类来处理==
两种实现方式的不同之处:
JDK动态代(dai)理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理。实现步骤大概如下:
- 定义一个实现接口InvocationHandler的类
- 通过构造函数,注入被代理类
- 实现invoke( Object proxy, Method method, Object[ ] args)方法
- 在主函数中获得被代理类的类加载器
- 使用Proxy.newProxyInstance( )产生一个代理对象
- 通过代(dai)理对象调用各种方法
cglib主要针对类实现代理,对是否实现接口无要求。原理是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以被代理的类或方法不可以声明为final类型。实现步骤大概如下:
- 定义一个实现了MethodInterceptor接口的类
- 实现其 intercept()方法,在其中调用proxy.invokeSuper( )
3、AOP与OOP区别
4、AOP通知类型
通知:被抽取有共性功能的代码逻辑
5种通知类型:
- 前置通知(Before):在目标方法被调用之前调用通知功能
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么
- 返回通知(After-returning):在目标方法成功执行之后调用通知
- 异常通知(After-throwing):在目标方法抛出异常后调用通知
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方
5、小结
6、面试题
(1)Spring中的AOP面向切面编程有了解吗?
AOP,面向切面编程 是指当需要在某一个方法之前或者之后做一些额外的操作,比如说日志记录,权限判断,异常统计等,可以利用AOP将功能代码从业务逻辑代码中分离出来。
AOP中有如下的操作术语:
Joinpoint(连接点): 类里面可以被增强的方法,这些方法称为连接点
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
Aspect(切面):是切入点和通知(引介)的结合
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或属性
Target(目标对象):代(dai)理的目标对象(要增强的类)
Weaving(织入):是把增强应用到目标的过程,把advice 应用到 target的过程
Proxy(代(dai)理):一个类被AOP织入增强后,就产生一个结果代(dai)理类
我们来简单理解下重要概念。切入点就是在类里边可以有很多方法被增强,比如实际操作中,只是增强了个别方法,则定义实际被增强的某个方法为切入点;通知/增强 就是指增强的逻辑,比如扩展日志功能,这个日志功能称为增强;切面就是把增强应用到具体方法上面的过程称为切面。
二、JDK和cglib动态代理demo
1、JDK动态代(dai)理Demo:
创建目标对象接口:
public interface IPeople {
public void fun();
public void func();
}
目标对象
/**
* @program: spring01
* @description: 实际被代理的类
* @author: CoderPengJiang
* @create: 2020-04-28 07:50
**/
//目标对象
public class People implements IPeople {
@Override
public void fun() {
System.out.println("这是fun方法");
}
@Override
public void func() {
System.out.println("这是func方法");
}
}
对目标对象进行代理并且进行功能增强的具体实现类
里面有两个方法func()和fun(),其中func()进行了功能增强,InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @program: spring01
* @description: 定义一个实现接口InvocationHandler的类
* @author: CoderPengJiang
* @create: 2020-04-28 07:52
**/
public class MyHandle implements InvocationHandler {
//定义目标对象
Object obj=null;
//我要代(dai)理谁
public MyHandle(Object obj){
this.obj=obj;
}
/**
*
* @param proxy:被代理的对象(不用)
* @param method:目标对象中的方法对象,jdk传过来
* @param args:是该方法中的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
if (method.getName().equals("func")){
//在目标对象方法的前后可以追加功能
System.out.println("前置通知");
//执行目标对象的方法
result=method.invoke(this.obj, args);//result为方法的返回值
System.out.println("后置通知");
return result;
}else{
result=method.invoke(this.obj, args);//result为方法的返回值
}
return result;
}
}
使用JDK的java.lang.reflect.Proxy类的newProxyInstance方法实现动态代理
public class DynamicProxy {
public static void main(String[] args){
//创建目标对象
IPeople ple=new People();
/**
* newProxyInstance方法的三个参数的三个意思:
* 1、loader:类加载器(类的字节码对象获得)写法固定,ple.getClass().getClassLoader()
* 2、interface得到该对象的所有实现接口的字节码对象的数组,写法固定ple.getClass().getInterfaces()
* 3、需要一个实现了InvocationHandler接口的对象,这步需要我们自己手动实现,对目标对象方法功能的增强就是在这个对象中完成的
*/
//定义一个handler
InvocationHandler handle=new MyHandle(ple);
//返回的是代理对象
IPeople newProxyInstance=(IPeople) Proxy.newProxyInstance(ple.getClass().getClassLoader(), ple.getClass().getInterfaces(), handle);
//执行代理对象的增强后的方法
newProxyInstance.func();
System.out.println("---------");
newProxyInstance.fun();
}
}
测试结果
2、cglib动态代理Demo
创建目标类:
public class Student {
public void study(){
System.out.println("正在学习--");
}
}
设置被增强的方法、回调的方法、拦截的方法
public class CallbackMethod implements MethodInterceptor {
/**
*
* @param o:代理的对象,需要返回
* @param method:目标对象的方法
* @param objects:目标对象方法的参数
* @param methodProxy:代理对象中的代理方法对象
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置通知");
//执行被拦截的方法,被增强的方法
Object o1=methodProxy.invokeSuper(o,objects);
System.out.println( "后置通知");
return o1;
}
}
测试
public class Test {
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();//1、空的字节码对象
enhancer.setSuperclass(Student.class);// 2、设定这个字节码对象的父类为student(目标对象的类)
Callback callback=new CallbackMethod();
enhancer.setCallback(callback);
//4、得到代理对象
Student sudent = (Student) enhancer.create();
sudent.study();
}
}
测试结果