java---代理模式
代理:在不修改目标对象的功能的前提下,通过代理对目标对象进行功能扩展
1. 静态代理
静态代理:
例子:
public interface UserDao{ void save(); }
public class UserDaoImpl implements UserDao { @Override public void save(){ System.out.println("保存数据"); } }
以上,UserImpl的方法save(),如果需要在操作之前开启事务、操作完后提交事务,则要这么写:
public class UserDaoImpl implements UserDao { @Override public void save(){ fun_session(); System.out.println("保存数据"); fun_commit(); } }
如果类中有很多方法,都需要操作之前开启事务,操作完后提交事务,则造成了 开启事务、提交事务 这部分冗余重复。我们抛弃掉上面这个写法,不修改UserDaoImpl,把额外的工作交给代理来实现,但是工作即save() 还是UserDaoImpl的对象来做的。
代理类:
public class UserDaoProxy implements UserDao { private UserDao dao; public UserDaoProxy(final UserDao dao) { this.dao = dao; } @Override public void save() { fun_session(); dao.save(); fun_commit(); } }
使用者:
UserDao dao = new UserDaoImpl(); //工作还是需要UserDaoImpl来做,需要这个对象 UserDao proxy = new UserDaoProxy(dao); //创建代理对象 proxy.save();
开启事务、提交事务的代码写在代理类里面
静态代理的问题:
如果接口改了,则代理也要改
代理需要实现接口,则有很多接口时,也会有相应很多代理类
2. 动态代理
2.1动态代理1:基于接口的
代理对象的产生时动态地在内存中构建,jdk中提供了相应的类
java.lang.reflect.Proxy
方法:
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interface,reflect.InvocationHandler h)
参数loader:目标对象类加载器
参数interface:目标对象实现的接口类型
参数h:指定的动态处理器,执行目标对象的方法时,会触发事件处理器的方法
例子:
接口:
public interface Person { void fun(); }
实现类:
public class XT implements Person{ @Override public void fun() { System.out.println("自己做了一些事情"); } }
代理:
public class TestProxy { XT x = new XT(); public Person getPersonProxy() { return (Person) Proxy.newProxyInstance(TestProxy.class.getClassLoader(), x.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("fun")) { System.out.println("代理做了一些事情"); method.invoke(x,args); } return null; } }); } }
使用:
TestProxy a = new TestProxy(); Person proxy = a.getPersonProxy(); proxy.fun();
换个写法:
//接口 public interface HelloService { public void say(); } //实现类 public class HelloServiceImpl implements HelloService { @Override public void say() { System.out.println("hello service"); } } //需要我们写的代理类 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("记录日志"); Object invoke = method.invoke(target, args); System.out.println("清理数据"); return invoke; } public Object getProxy(){ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this); } }
HelloService service = new HelloServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(service); HelloService proxy = (HelloService) handler.getProxy(); proxy.say();
2.2 动态代理2:CGLIB代理
前面的动态代理需要目标类有实现的接口,不然Proxy.newProxyInstace的第二个参数缺少
CGLIB使用了很底层的字节码技术,为一个类创建子类,并在子类中采用方法拦截的技术去拦截父类方法的调用。
不能对final类代理(final类不能被继承)
目标对象的 final、static方法不会被拦截
jar包:https://mvnrepository.com/artifact/cglib/cglib-nodep/3.3.0
package src.basegrammer.proxyTest; 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 CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { //设置需要创建子类的类 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //通过字节码技术动态创建子类实例 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("记录日志"); //代理类调用父类方法 Object result = proxy.invokeSuper(obj, args); System.out.println("清理数据"); return result; } }
public void cglibTest(){ CglibProxy proxy = new CglibProxy(); //通过生成子类的方式创建代理类 HelloServiceImpl proxyImp = (HelloServiceImpl) proxy.getProxy(HelloServiceImpl.class); proxyImp.say(); }