Spring AOP 之代理模式
一、静态代理
静态代理,代理类和被代理的类实现了同样的接口,只能代理特定的类。
定义一个接口
public interface Service { public void delete(); public void update(); public void insert(); }
被代理类
public class StudentServiceImpl implements Service { @Override public void delete() { System.out.println("删除学生信息!!!"); } @Override public void update() { System.out.println("修改学生信息!!!"); } @Override public void insert() { System.out.println("添加学生信息!!!"); } }
代理类
public class StaticProxy implements Service { private Service service; public StaticProxy(Service service) { this.service = service; } public void delete() { open(); service.delete(); commit(); } public void update() { open(); service.update(); commit(); } public void insert() { open(); service.insert(); commit(); } public void open(){ System.out.println("开启事务!!!"); } public void commit(){ System.out.println("提交事务!!!"); } }
4.测试类
public class Test { public static void main(String[] args) { //被代理类 StudentServiceImpl student = new StudentServiceImpl(); //被代理类的代理对象 StaticProxy proxy = new StaticProxy(student); //通过代理对象调用被代理类的方法 proxy.delete(); } }
运行结果:
被代理类只需负责自己特定的业务,而代理类则负责业务的扩展,比如执行被代理类的方法前要开启事务,执行之后要提交事务,我们就不需要给每个方法都添加开启事务和提交事务。
代理类就会负责完成这些工作。
静态代理的优缺点:
- 优点:
- 被代理类只需负责核心业务
- 业务逻辑的扩展更加方便
- 通用代码放到代理类中,提高了代码的复用性
- 缺点:
- 被代理类太多,就会导致工作量变大,开发效率降低
二、动态代理
动态代理,由AOP框架动态生成的一的对象,对象可以作为目标对象使用。
动态代理有两种方式:
- JDK动态代理
- CGLIB代理
2.1 JDK动态代理
基于接口的动态代理,只能为实现了接口的类动态代理对象
创建一个接口并创建一个它的实现类并重写它的方法。
创建一个类实现InvocationHandler接口,并重写invoke方法
public class JdkDynamicProxy implements InvocationHandler { //被代理的对象 private Object object; public JdkDynamicProxy(Object object) { this.object = object; } //产生代理对象,返回代理对象 public Object getProxy(){ //1.获取被代理对象的类加载器 ClassLoader classLoader = object.getClass().getClassLoader(); //2.获取被代理对象实现的所有接口 Class<?>[] interfaces = object.getClass().getInterfaces(); //3.创建代理对象 //classloader:类加载器来定义代理类 //interfaces:代理类实现的接口列表 //this:调度方法调用的调用处理函数 Object o = Proxy.newProxyInstance(classLoader, interfaces,this); return o; } //处理代理实例,返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log(method.getName()); Object invoke = method.invoke(object,args); return invoke; } //定义一个打印日志的方法 public void log(String msg){ System.out.println("执行了"+ msg +"方法!"); } }
测试
public class DynamicProxyTest { public static void main(String[] args) { //创建被代理类对象 StudentServiceImpl studentService = new StudentServiceImpl(); //创建代理对象,产生的代理对象可以强转成被代理对象实现的接口类型 JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(studentService); Service proxy = (Service) jdkDynamicProxy.getProxy(); //使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的invoke方法 //调用的方法作为一个参数,传给invoke方法 proxy.delete(); } }
运行结果:
2.2 CGLib代理
使用JDK动态代理的对象必须是实现了一个或多个接口的,如果要对没有实现接口的类创建代理对象,就要使用CGLIB代理。
基于类的动态代理—CGlib
CGLib是一个高性能开源的代码生成包,因在Spring的核心包中已包含CGLib所需要的包,所以不再需要添加依赖。
创建一个StudentServiceImpl 类,并添加增删改方法。
创建一个类,实现MethodInterceptor接口,并重写intercept方法。
/** * CGLIB代理 */ public class CGLibDynamicProxy implements MethodInterceptor { private Object object; public CGLibDynamicProxy(Object object) { this.object = object; } //创建并返回代理对象 //该代理对象是通过被代理类的子类来创建的 public Object getProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(object.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { log(method.getName()); Object invoke = method.invoke(object, args); return invoke; } //定义一个打印日志的方法 public void log(String msg){ System.out.println("执行了"+ msg +"方法!"); } }
测试
public class DynamicProxyTest { public static void main(String[] args) { //创建被代理类对象 StudentServiceImpl studentService = new StudentServiceImpl(); //创建代理对象,产生的代理对象可以强转成被代理类类型 CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(studentService); StudentServiceImpl proxy = (StudentServiceImpl) cgLibDynamicProxy.getProxy(); //使用代理对象调方法,不会执行调用的方法,而是进入到创建代理对象时指定的intercept方法 //将调用的方法以及方法中的参数传给intercept方法 proxy.insert(); } }
运行结果:
动态代理的优点:被代理类只需负责核心业务;
业务逻辑的扩展更加方便;
通用代码放到代理类中,提高了代码的复用性;
一个动态代理 , 一般代理某一类业务;
一个动态代理可以代理多个类,代理的是接口。