代理模式:是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
示例:火车票代售就是代理模式的体现,我们可以从火车票代售点买火车票,代售点代理了火车站对象,提供了买火车票的方法
一:静态代理
- 前提:需要代理对象和目标对象实现一样的接口
- 优点:可以在不修改目标对象的前提下,扩展目标对象的功能
- 缺点:如果目标对象的方法发生改变,比如方法名做了修改,则代理类也要做修改
/** * 接口 * @author Ethon * */ public interface Person { void add(); }
/** * 目标对象 * @author Ethon * */ public class Student implements Person { @Override public void add() { System.out.println("这是目标对象中的add()方法"); } }
/** * 代理对象 * @author Ethon * */ public class StudentProxy implements Person{ //目标对象 private Student student; public StudentProxy(Student student){ this.student = student; } @Override public void add() { System.out.println("开启事务..."); // 扩展功能 student.add(); System.out.println("提交事务..."); } }
/** * 测试类 * @author Ethon * */ public class Test { public static void main(String[] args){ //目标对象 Student student = new Student(); //代理对象 StudentProxy proxy = new StudentProxy(student); proxy.add(); } }
输出结果:
开启事务...
这是目标对象中的add()方法
提交事务...
---------------------------------------------------------- 分隔线 ----------------------------------------------------------
二、动态代理
代理类在程序运行时创建的代理方式被成为动态代理,动态代理对象不需要实现接口,但目标对象必须实现接口。
静态代理与动态代理的区别:
- 静态代理在编译时就已经实现,编译完成后代理类就是一个实际的class文件
- 动态代理在运行时动态生成字节码,并加载到jvm中
JDK的动态代理:在java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。
/** * 接口 * @author Ethon * */ public interface Person { void add(); }
/** * 目标对象 * @author Ethon * */ public class Student implements Person { @Override public void add() { System.out.println("这是目标对象中的add()方法"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author Ethon * */ public class StuInvocationHandler implements InvocationHandler{ //目标对象 private Object target; public StuInvocationHandler(Object target){ this.target = target; } /** * proxy: 动态代理对象 * method:正在执行的方法 * args:调用目标方法时传入的实参 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务..."); // 扩展功能 Object obj = method.invoke(target, args); System.out.println("提交事务..."); return obj; } }
/** * 测试类 * @author Ethon * */ public class Test { public static void main(String[] args){ //目标对象 Person student = new Student(); //创建一个与代理对象相关联的InvocationHandler InvocationHandler handler = new StuInvocationHandler(student); //得到代理对象 Person studentProxy = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), Student.class.getInterfaces(), handler); studentProxy.add(); } }
输出结果:
开启事务...
这是目标对象中的add()方法
提交事务...
---------------------------------------------------------- 分隔线 ----------------------------------------------------------
cglib的动态代理:CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法。
/** * 业务类 * @author Ethon * */ public class Student { /** * 该方法不能被子类覆盖,cglib是无法代理final修饰的方法的 */ final public void sing(){ System.out.println("sing..."); } public void study(){ System.out.println("study..."); } }
import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * 方法拦截器 * @author Ethon * */ public class MyMethodInterceptor implements MethodInterceptor{ /** * obj:表示增强的对象,即实现这个接口类的一个对象 * method:表示要被拦截的方法 * args:表示要被拦截方法的参数 * proxy:表示要触发父类的方法对象 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("开启事务..."); //扩展功能 Object object = proxy.invokeSuper(obj, args); System.out.println("提交事务..."); return object; } }
import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.proxy.Enhancer; /** * 测试类 * @author Ethon * */ public class Test { public static void main(String[] args){ //代理类class文件存入本地磁盘 //System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D\\code"); //通过cglib动态代理获取代理对象的过程 Enhancer enhancer = new Enhancer(); //设置enhancer对象的父类 enhancer.setSuperclass(Student.class); //设置enhancer的回调对象 enhancer.setCallback(new MyMethodInterceptor()); //创建代理对象 Student stuProxy = (Student) enhancer.create(); //通过代理对象调用目标方法 //调用方法时,在代理类中会先判断是否实现了方法拦截的接口,如果实现了那就会被方法拦截器拦截,没实现的话直接调用目标类的方法 stuProxy.study(); } }
输出结果:
开启事务...
study...
提交事务...