为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
静态代理、动态代理(JDK代理和cglib代理)
静态代理和JDK代理都是实现接口,cglib是可以实现类。
举例:老师生病了,找来代课老师。其中有一个共有的功能就是上课,代课老师只关注上课就好,擦黑板的行为交给别人就好(代理对象)
首先,构建接口,其中有一个共有的功能
//公用的功能 public interface ITeacher { void teach(); }
目标对象/真实对象
//目标对象 public class Teacher implements ITeacher { @Override public void teach() { System.out.println("开始上课!!!!"); } }
代理对象
//代理对象 public class TeacherProxy implements ITeacher { //代理对象中引入目标对象 private ITeacher teacher; public TeacherProxy(ITeacher teacher) { this.teacher = teacher; } @Override public void teach() { System.out.println("擦黑板"); teacher.teach(); System.out.println("下课了!!!!"); } }
调用方法
public class Client { public static void main(String[] args) { //引入目标对象 Teacher teacher = new Teacher(); //引入代理对象 TeacherProxy teacherProxy = new TeacherProxy(teacher); //通过代理对象 调用其中的方法 teacherProxy.teach(); } }
结果
"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\study\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=55176:D:\study\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\study\workspace\workspace_idea_designMode\out\production\Proxy" com.ccunix.staticProxy.Client 擦黑板 开始上课!!!! 下课了!!!!
优点:在不修改目标对象功能的前提下,通过代理对象进行扩展功能。
缺点:因为目标对象和代理对象都实现了相同的接口,一旦接口中的方法增加,那么就需要维护代理对象和目标对象。
动态代理介绍:
代理对象不需要实现接口,但是目标对象必须实现接口,否则不可以使用动态代理。这个是前提
代理对象的生成用到了JDK的API,也就是反射。动态的在内存中生成代理对象。
首先有个接口
public interface ITeacher { void teach(); void sayHello(); }
目标对象
public class Teacher implements ITeacher { @Override public void teach() { System.out.println("开始上课!!!"); } @Override public void sayHello() { System.out.println("同学们好!!"); } }
动态获得代理对象
public class ProxyFactory { private Object target; public ProxyFactory(Object target) { this.target = target; } /* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 1、classloader类加载器 获取类加载器的方法是固定的 2、interfaces 就是目标对象实现的接口 3、InvocationHandler 使用匿名内部类获取 * */ public Object getInstanceProxy(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理"); Object result = method.invoke(target, args); System.out.println("下课吧!!!"); return result; } }); } }
Client类
public class Client { public static void main(String[] args) { ITeacher teacher = new Teacher(); //代理工厂会根据目标对象生成代理工厂 ProxyFactory proxyFactory = new ProxyFactory(teacher); //获取代理对象 ITeacher proxy = (ITeacher)proxyFactory.getInstanceProxy(); proxy.sayHello();
//说明会根据方法的名字和参数进行分辨要执行的是哪个方法 proxy.teach();
最大的区别就是目标对象不需要再实现接口了,这个时候用目标对象的子类来实现代理,这就是cglib代理,Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。
在AOP编程中如何选择代理模式:
1.目标对象需要实现接口,用JDK代理
2.目标对象不需要实现接口,用Cglib代理
目标对象
public class Teacher { public void teach(){ System.out.println("开始上课"); } }
代理工厂
public class ProxyFactory implements MethodInterceptor { //聚合目标对象 private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance(){ //1、创建一个工具类 Enhancer enhancer = new Enhancer(); //2、设置父类 enhancer.setSuperclass(target.getClass()); //3、设置回调函数 就是去调用拦截器 enhancer.setCallback(this); //4、创建子类对象,就是代理对象 return enhancer.create(); } public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("擦黑板"); Object result = method.invoke(target, args); System.out.println("下课吧!!!"); return result; } }
client类
public class Client { public static void main(String[] args) { Teacher teacher = new Teacher(); //通过工具类生成代理对象 Teacher proxyInstance = (Teacher) new ProxyFactory(teacher).getProxyInstance(); //代理对象执行方法时会触发拦截器,从而实现对目标对象方法的调用 proxyInstance.teach(); } }
原文:https://www.cnblogs.com/sc19/p/14383628.html