回顾一下AOP相关概念
SpringAOP的理解和底层原理
补充
引介(Introduction):特殊的增强,动态为类增加方法
织入(Weaving):将增强加入到目标类的过程,织入分为三种时期
- 编译器:AspectJ (上文讲过)
- 类加载
- 运行期:jdk动态代理(实现接口),CGlib(子类,不能用final)
目标对象(Target):原始对象
代理对象(Proxy):加入了增强的对象,是生成的;
切面(Aspect):切点 + 增强
本文要说的就是在运行期间织入的两种实现方式之 jdk动态代理
什么是代理模式呢?
代理模式有三个角色,分别是
- 抽象角色:接口
- 目标角色:实现类
- 代理角色:实现接口(InvocationHandler),并引用目标角色
代理模式与装饰者模式的区别
类图(结构)基本一样,但目的不同,装饰模式的前提是已经所有的类,并进行组装;
而使用代理模式时,我们不能直接访问目标角色或没有权限访问时,可以使用代理模式
代理模式分为两种
- 静态代理:需要为每个目标角色,创建一个对应的代理角色;类的数量会急剧膨胀
- 动态代理:自动为每个目标角色生成对应的代理角色
接下来就是jdk动态代理的具体实现代码:
实现jdk动态代理的前提是所有的目标类都必须要基于一个统一的接口
定义一个统一的接口
package aopstudy.demo.TestAopByJdk;
public interface UserDao {
int add(int a, int b);
String update(String id);
}
定义目标对象,实现统一的接口
package aopstudy.demo.TestAopByJdk;
public class UserDaoImp implements UserDao {
public int add(int a, int b) {
System.out.println("执行add方法");
return a + b;
}
public String update(String id) {
System.out.println("执行update方法");
return id;
}
}
创建代理角色
//创建的类得需要实现InvocationHandler,并重写invoke()方法
class UserProxy implements InvocationHandler {
// 创建谁的代理对象,把谁传进来
// 通过有参数构造方法传入,参数可以UserDaoImp,亦可以用 Object
private Object obj;
public UserProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑部分
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前执行
// method.getName():当前执行方法的名字, args:当前执行方法传递的参数
System.out.println("方法之前执行.....方法名:" + method.getName() + "传递的参数:" + Arrays.toString(args));
//被增强的方法执行
// method.invoke 俩个参数 (方法名,方法参数)
Object res = method.invoke(obj, args);
//方法之后执行
System.out.println("方法之后执行.....方法名:" + obj);
return res;
}
}
编写测试代码
public class JdkProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
//目标类必须基于统一的接口
UserDao userDao = new UserDaoImp();
//创建接口实现类代理对象中,newProxyInstance有三个参数,ClassLoader类加载器,,interfaces接口类列表,UserProxy代理角色
UserDao dao = (UserDao) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), interfaces, new UserProxy(userDao));
int result = dao.add(1, 2);
System.out.println(result);
System.out.println("-----------------------------------------------------");
String idRes = dao.update("Jdk Proxy");
System.out.println(idRes);
}
}
运行结果:
方法之前执行.....方法名:add传递的参数:[1, 2]
执行add方法
方法之后执行.....方法名:aopstudy.demo.TestAopByJdk.UserDaoImp@5e481248
3
-----------------------------------------------------
方法之前执行.....方法名:update传递的参数:[Jdk Proxy]
执行update方法
方法之后执行.....方法名:aopstudy.demo.TestAopByJdk.UserDaoImp@5e481248
Jdk Proxy