三种代理模式
静态代理
被代理类和代理类需要==实现同一个接口==
-
先创建一个共同的接口IUserDao接口
package top.lukeewin.demo21; public interface IUserDao { void save(); }
-
创建被代理类,该被代理类(目标类)要实现IUserDao接口
package top.lukeewin.demo21; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存数据"); } }
-
创建代理类,该代理类要实现IUserDao接口
package top.lukeewin.demo21; public class UserDaoProxy implements IUserDao { private IUserDao target; public UserDaoProxy(IUserDao target) { this.target = target; } @Override public void save() { System.out.println("开启事务"); target.save(); System.out.println("提交事务"); } }
-
创建测试类和测试方法
package top.lukeewin.demo21; import org.junit.Test; public class ProxyTest { @Test public void testStaticProxy() { //目标对象 IUserDao target = new UserDao(); //代理对象 UserDaoProxy proxy = new UserDaoProxy(target); proxy.save(); } }
-
运行结果
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:会产生过多的代理类。
动态代理
利用JDK自带的API动态的在内存中构建代理对象。动态代理又称为接口代理或JDK代理
动态代理中的代理对象不需要实现接口,但是要求被代理对象必须实现接口,否则不能使用动态代理。
-
接口类
package top.lukeewin.demo21; public interface IUserDao { void save(); }
-
目标类
package top.lukeewin.demo21; public class UserDao implements IUserDao{ @Override public void save() { System.out.println("保存数据"); } }
-
动态代理类
package top.lukeewin.demo21; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class UserProxyFactory { private Object target; //维护一个目标对象 public UserProxyFactory(Object target) { this.target = target; } //为目标对象生成代理对象 public Object getProxyInstance() { 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("开启事务"); //执行目标对象方法 Object returnValue = method.invoke(target, args); System.out.println("提交事务"); return null; } }); } }
-
测试类
package top.lukeewin.demo21; import org.junit.Test; public class ProxyTest { @Test public void testDynamicProxy() { IUserDao target = new UserDao(); System.out.println(target.getClass()); //输出目标对象信息 IUserDao proxy = (IUserDao) new UserProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //输出代理对象信息 proxy.save(); //执行代理方法 } }
-
运行结果
分析:
-
用到了
java.lang.reflect.Proxy
类中的静态方法newProxyInstance
static Object newProxyInstance(ClassLoader loader, //指定当前目标对象使用类加载器 Class<?>[] interfaces, //目标对象实现的接口的类型 InvocationHandler h //事件处理器 ) //返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
-
还用到了
java.lang.reflect.InvocationHandler
中的invoke
方法Object invoke(Object proxy, Method method, Object[] args) // 在代理实例上处理方法调用并返回结果。
cglib代理
cglib是一个第三方的代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
-
首先先要在maven中引入cglib的坐标。注意:如果是已经引入了Spring-core的jar包,则不用再引入cglib的jar包了。
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency>
-
目标类
package top.lukeewin.maven; public class UserDao { public void save() { System.out.println("保存数据"); } }
-
代理类: 需要实现
MethodInterceptor
接口,并重写intercept
方法package top.lukeewin.maven; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class ProxyFactory implements MethodInterceptor { private Object target; public ProxyFactory(Object target) { this.target = target; } //为目标对象生成代理对象 public Object getProxyInstance() { //工具类 Enhancer en = new Enhancer(); //设置父类 en.setSuperclass(target.getClass()); //设置回调函数 en.setCallback(this); //创建子类对象代理 return en.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开启事务"); //执行目标对象的方法 Object returnValue = method.invoke(target, objects); System.out.println("关闭事务"); return null; } }
-
测试类
package top.lukeewin.maven; import org.junit.jupiter.api.Test; public class TestProxy { @Test public void testCglibProxy() { //目标对象 UserDao target = new UserDao(); System.out.println(target.getClass()); //代理对象 UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); System.out.println(proxy.getClass()); //执行代理对象方法 proxy.save(); } }
-
运行结果
本文出自个人博客https://blog.lukeewin.top