1 预备知识
1.1 静态代理和动态代理
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。
静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大。
先列出接口和Aspect类。
public interface UserService {
public void addUser();
public void updateUser();
public void deleteUser();
}
public class MyAspect {
public void before(){
System.out.println("before.....");
}
public void after(){
System.out.println("after.....");
}
}
静态代理示例如下,实际就是代码直接写死。:
public class UserServiceProxy implements UserService {
private UserService userService ;
public UserService Proxy(UserService userService ) {
this.userService = userService;
}
//以addUser()为例,其他两个方法略
@Override
public void addUser() {
MyAspect myAspect = new MyAspect();
myAspect.before();
userService.addUser();
myAspect.after();
}
}
1.2 JDK动态代理
public class UserServiceProxy {
public static UserService createService(){
//1 目标类
final UserService userService = new UserServiceImpl();
//2切面类
final MyAspect myAspect = new MyAspect();
/* 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面
* Proxy.newProxyInstance
* 参数1:loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。
* 一般情况:当前类.class.getClassLoader();
* 目标类实例.getClass().get...
* 参数2:Class[] interfaces 代理类需要实现的所有接口
* 方式1:目标类实例.getClass().getInterfaces() ;注意:只能获得自己接口,不能获得父元素接口
* 方式2:new Class[]{UserService.class}
* 例如:jdbc 驱动 --> DriverManager 获得接口 Connection
* 参数3:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部
* 提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke
* 参数31:Object proxy :代理对象
* 参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
* 执行方法名:method.getName()
* 执行方法:method.invoke(对象,实际参数)
* 参数33:Object[] args :方法实际参数
*
*/
UserService proxService = (UserService)Proxy.newProxyInstance(
MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前执行
myAspect.before();
//执行目标类的方法
Object obj = method.invoke(userService, args);
//后执行
myAspect.after();
return obj;
}
});
return proxService;
}
}
1.3 CGLIB代理
CGLIB适用于代理对象没有接口,只有类这一情况,代码比jdk动态代理要简洁:
public class MyBeanFactory {
public static UserServiceImpl createService(){
//1 目标类
final UserServiceImpl userService = new UserServiceImpl();
//2切面类
final MyAspect myAspect = new MyAspect();
// 3.代理类 ,采用cglib,底层创建目标类的子类
//3.1 核心类
Enhancer enhancer = new Enhancer();
//3.2 确定父类
enhancer.setSuperclass(userService.getClass());
/* 3.3 设置回调函数 , MethodInterceptor接口 等效 jdk InvocationHandler接口
* intercept() 等效 jdk invoke()
* 参数1、参数2、参数3:以invoke一样
* 参数4:methodProxy 方法的代理
*
*
*/
enhancer.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//前
myAspect.before();
//执行目标类的方法
Object obj = method.invoke(userService, args);
// * 执行代理类的父类 ,执行目标类 (目标类和代理类 父子关系)
methodProxy.invokeSuper(proxy, args);
//后
myAspect.after();
return obj;
}
});
//3.4 创建代理
UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
return proxService;
}
}
2 正式知识
这一篇讲的非常详细,强烈推荐:Spring源码深度解析(AOP功能源码解析):https://blog.csdn.net/qq_26323323/article/details/81012855
注:文章在JDK动态代理的最后的invocation.proceed()没有进行详解,我debug了一下,这里的功能可以这么理解:invoke()方法里会获得接口的代理对象,并将其所有的advice组成一条chain,然后按照一定的顺序依次调用增强器的相关方法,实现切入。
附源码流程图: