今天学到Spring的动态代理实现AOP,对代理这个概念很模糊,看了一篇文章发现这是一种设计模式,因而学习记录一下。html
代理模式是一种对象结构型的模式,主要为其余对象提供一种代理以控制对这个对象的访问。简单点说就是你访问一个对象并非直接的访问它,而是经过一个代理简介访问,那么这个代理就能够在访问对象以前或以后作一些定制化的操做,好比校验入参,打印日志什么的。Spring AOP就是一个代理模式的典型应用。java
java中的代理分为三类:静态代理、动态代理和Cglib代理。下面依次讲解着三种代理。编程
静态代理在使用时,须要定义接口或者父类,被代理的对象和代理对象须要一块儿实现同一个接口或者继承同一个父类。设计模式
代码示例缓存
接口:框架
package com.wangjun.designPattern.proxy; /* * 咱们有一我的类的接口,有不少种职业,好比教师,学生 */ public interface Person { //获取本职业的职责 public String getDuty(); }
目标对象1:ide
package com.wangjun.designPattern.proxy; public class Student implements Person { @Override public String getDuty() { return "学习知识"; } }
目标对象2:函数
package com.wangjun.designPattern.proxy; public class Teacher implements Person { @Override public String getDuty() { return "教书育人"; } }
代理对象:工具
package com.wangjun.designPattern.proxy; import java.util.HashMap; import java.util.Map; /* * 经过代理,加入缓存功能 */ public class CachedPersonProxy implements Person{ private Person person; private Map<Person,String> map = new HashMap<>();; public CachedPersonProxy(Person person) { this.person = person; } @Override public String getDuty() { String duty = map.get(person); if(null == duty) { duty = person.getDuty(); map.put(person, duty); } return duty; } }
测试类:性能
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Teacher teacher = new Teacher(); CachedPersonProxy proxy = new CachedPersonProxy(teacher); System.out.println(proxy.getDuty()); } }
静态代理总结:
动态代理也叫JDK代理或者接口代理。
动态代理有如下特色:
代理类所在的包是:java.lang.reflect.Proxy
JDK实现动态代理只须要使用newProxyInstance方法,该方法须要传入三个变量:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
代码示例
接口类Person.class和实现类Teacher.class、Sutdent.class不变,在这个基础上,增长一个代理工厂类ProxyFactory.java,而后在测试类(须要使用到代理的代码)中先创建目标对象和代理对象的联系,接着代用代理对象的中同名方法。
代理工厂类:
package com.wangjun.designPattern.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; public class ProxyFactory { private Person person; private Map<Person, String> map = new HashMap<>(); public ProxyFactory(Person person) { this.person = person; } public Object getProxyInstance() { return Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String duty = map.get(person); if(null == duty) { //执行对象方法 System.out.println("没有缓存"); duty = (String) method.invoke(person, args); map.put(person, duty); } return duty; } }); } }
测试类:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { Person teacher = new Teacher(); System.out.println(teacher.getClass()); //使用动态代理 ProxyFactory proxyFactory = new ProxyFactory(teacher); Person teacherProxy = (Person) proxyFactory.getProxyInstance(); System.out.println(teacherProxy.getClass()); System.out.println(teacherProxy.getDuty()); System.out.println(teacherProxy.getDuty()); } }
总结
代理对象不须要实现接口,可是目标对象必定要实现接口,不然不能用动态代理。
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,可是有时候目标对象只是一个单独的对象,并无实现任何的接口,这个时候就可使用以目标对象子类的方式类实现代理,这种方法就叫作:Cglib代理。
Cglib子类实现代理的方法
代码示例
目标对象类:
package com.wangjun.designPattern.proxy; /* * 目标对象,没有实现任何接口 */ public class Doctor { public String getDuty() { return "救死扶伤"; } }
Cglib代理工厂类:
package com.wangjun.designPattern.proxy; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /* * cglib代理工厂 * 对Doctor在内存中动态构建一个子类对象 */ public class CglibProxyFactory implements MethodInterceptor { private Object person; private Map<Object, String> map = new HashMap<>(); public CglibProxyFactory(Object person) { this.person = person; } // 给目标对象建立一个代理对象 public Object getProxyInstance() { // 1.工具类 Enhancer en = new Enhancer(); // 2.设置父类 en.setSuperclass(person.getClass()); // 3.设置回调函数 en.setCallback(this); // 4.建立子类(代理对象) return en.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { String duty = map.get(person); if(null == duty) { //执行目标对象的方法 System.out.println("cglib实现,有缓存"); duty = (String) arg1.invoke(person, arg2); map.put(person, duty); } return duty; } }
测试类:
package com.wangjun.designPattern.proxy; public class Main { public static void main(String[] args) { // 使用cglib // 目标对象 Doctor target = new Doctor(); System.out.println(target.getClass()); // 代理对象 Doctor proxyCglib = (Doctor) new CglibProxyFactory(target).getProxyInstance(); // 执行代理对象的方法 System.out.println(proxyCglib.getClass()); System.out.println(proxyCglib.getDuty()); System.out.println(proxyCglib.getDuty()); } }
在Spring的AOP编程中: