动态代理:当想要给实现了某个接口的类中的方法,加一些额外的处理。比如说加日志,加事务等。可以给这个类创建一个代理,故名思议就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新类。这个代理类并不是定义好的,是动态生成的。具有解耦意义,灵活,扩展性强。
动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler(将实现接口的类的对象传递给它)处理类。再有一个工具类Proxy(习惯性将其称为代理类,因为调用他的newInstance()可以产生代理对象,其实他只是一个产生代理对象的工具类)。利用到InvocationHandler,拼接代理类源码,将其编译生成代理类的二进制码,利用加载器加载,并将其实例化产生代理对象,最后返回。
静态代理: 优点: 1、 实现松散耦合。 2、做到在不修改目标对象的功能前提下,对目标功能扩展。
缺点: 如果项目中有多个类,则需要编写多个代理类,工作量大,不好修改,不好维护,不能应对变化。
创建接口
public interface Examable { void exam(); }创建学生类实现接口
public class Student implements Examable { @Override public void exam() { System.out.println("超级无敌棒棒糖!"); } }创建代理对象
public class Cheater implements Examable { //被代理对象 private final Examable student; public Cheater(Examable student){ this.student=student; } @Override public void exam() { System.out.println("现场漂移"); student.exam();//调用Student类的方法 } }测试
public class MainTest { //组合优于继承 public static void main(String[] args) { //cheater 就是一个代理对象 //因为它是受student 委托,完成某个功能 //它要完成的主要功能,来自student //除了委托做的事情,可能还会扩展一些行为 Examable ex = new Student();//原来的行为 ex .exam(); System.out.println("------下面是代理行为------"); Examable cheater = new Cheater(xiaoming); cheater.exam(); } }在maven仓库找到cglib依赖
创建类
public class Student { public void exam(){ System.out.println("超级无敌棒棒糖!"); } }创建CglibProxy类实现接口
package com.nf147.sim.proxy.p5; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class CglibProxy implements MethodInterceptor { /* * 参数 * Object 为由CGLib动态生成的代理类实例 * method 为上文中实体类所调用的被代理的方法引用 * objects 为参数值列表 * methodProxy 为生成的代理类对方法的代理引用 * return 从代理实例的方法调用返回的值 * */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o, objects); } }测试
package com.nf147.sim.proxy.p5; import com.nf147.sim.proxy.p1.Student; import net.sf.cglib.proxy.Enhancer; public class Main { public static void main(String[] args) { //第一种方式 //增强器,动态代码生成器 Enhancer enhancer = new Enhancer(); //设置 生成类 的 父类 enhancer.setSuperclass(Student.class); //回调函数 enhancer.setCallback(new CglibProxy()); //动态生成字节码并返回代理对象 Student o = (Student) enhancer.create(); o.exam(); System.out.println("-----------"); //第二种方式 //这里是简化写法 //第一个参数 设置 生成类 的父类 ,第二参数 被代理类的所有接口 ,回调函数 Student student = (Student) Enhancer.create(Student.class, null, new CglibProxy()); student.exam(); } }创建接口
public interface Examable { void exam(); }创建一个类,实现接口
public class Student implements Examable { @Override public void exam() { System.out.println("超级无敌棒棒糖!"); } }创建JdkProxy类,实现 InvocationHandler 接口
public class JdkProxy implements InvocationHandler { private Object object;//被代理 public JdkProxy() { } public JdkProxy(Object object) { this.object = object; 初始化的时候就赋值 } /** * 当用户调用对象中的每个方法时都通过下面的方法执行,方法必须在接口 * proxy 被代理后的对象 * method 将要被执行的方法信息(反射) * args 执行方法时需要的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) { Object invoke = null; try { invoke = method.invoke(object, args); } catch (Exception e) { System.out.println("异常的信息" + e.getMessage()); } return invoke;//调用被代理对象原来的方法(行为) } }测试
public class MainTest { public static void main(String[] args) { /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数person1.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ ClassLoader cl= Thread.currentThread().getContextClassLoader(); Examable o = (Examable) Proxy.newProxyInstance( cl,//类加载器 new Class[]{Examable.class},//获取被代理对象的所有接口 new JdkProxy(new Student())//InvocationHandler对象 ); o.exam();//代理后的行为 } }