一、介绍
AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。
AOP代理主要分为静态代理和动态代理:
- 静态代理:以AspectJ为代表,在编译阶段生成AOP代理类---修改字节码
- 动态代理:以Spring AOP为代表。不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
二、Spring AOP的原理
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
1. JDK动态代理
- 通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
- JDK动态代理的核心是
InvocationHandler
接口和Proxy
类。
2. CGLIB动态代理
- CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,
- CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为
final
,那么它是无法使用CGLIB做动态代理的。
3. Spring AOP的实现
- 如果目标对象是接口类,就使用JDK动态代理;
- 否则,Spring会使用CGLIB动态代理。
三、JDK动态代理的使用
1. 创建目标对象的接口及实现类
/**
* 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
*/
public interface UserService {
/**
* 目标方法
*/
public void add();
}
2. 创建目标对象
/**
* 目标对象
*/
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("--------------------add---------------");
}
}
3. 实现自己的InvocationHandler
/**
* 实现自己的InvocationHandler
*/
public class MyInvocationHandler implements InvocationHandler {
// 目标对象
private Object target;
/**
* 构造方法
* @param target 目标对象
*/
public MyInvocationHandler(Object target) {
super();
this.target = target;
}
/**
* 执行目标对象的方法
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在目标对象的方法执行之前简单的打印一下
System.out.println("------------------before------------------");
// 执行目标对象的方法
Object result = method.invoke(target, args);
// 在目标对象的方法执行之后简单的打印一下
System.out.println("-------------------after------------------");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
target.getClass().getInterfaces(), this);
}
}
4. 测试
/**
* 动态代理测试类
*/
public class ProxyTest {
public static void main(String[] args) {
// 实例化目标对象
UserService userService = new UserServiceImpl();
// 实例化InvocationHandler
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
// 根据目标对象生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
// 调用代理对象的方法
proxy.add();
}
}
结果:
------------------before------------------
--------------------add---------------
-------------------after------------------
四、Cglib动态代理的使用
1. 创建目标对象
//被代理类
public class InfoDemo {
public void welcome (String person){
System.out.println("welcome :" + person);
}
}
2. 实现自己的MethodInterceptor
public class MyCglibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before...");
Object result = methodProxy.invokeSuper(obj, args);
System.out.println("after...");
return result;
}
public static Object getProxy(Class cls, MethodInterceptor interceptor){
Enhancer enhancer = new Enhancer();
//生成指定类的子类,也就是重写类中的业务方法
enhancer.setSuperclass(cls);
//设置回调函数,加入intercept()方法
enhancer.setCallback(interceptor);
return enhancer.create();
}
public static void main(String[] args) {
InfoDemo infoDemo = (InfoDemo)getProxy(InfoDemo.class, new MyCglibInterceptor());
infoDemo.welcome("ketty");
}
}
3. 测试结果
before...
welcome :ketty
after...