什么是代理模式
所谓代理模式就是为目标对象提供另外一种访问方式,通过访问代理对象来间接访问目标对象。优点是在不修改原来方法的情况下,给现有的对象中的方法追加额外的功能,即扩展目标对象的功能。代理模式又分为静态代理和动态代理两种,动态代理又分为JDK动态代理和cglib动态代理。
静态代理
使用静态代理需要定义三个类,定义一个接口或父类,让代理对象和被代理对象同时实现或继承父类。代理对象中维护一个被代理对象,并追加额外的功能。
/** * 接口 * Created by hang on 2018/3/13. */ public interface UserDao { void save(); }
/** * 实现接口的目标对象(被代理对象) * Created by hang on 2018/3/13. */ public class UserDaoImp implements UserDao{ public void save() { System.out.println("---保存成功---"); } }
/** * 实现接口的代理对象 * Created by hang on 2018/3/13. */ public class UserDaoProxy implements UserDao{ private UserDao userDao; public UserDaoProxy(UserDao userDao){ this.userDao = userDao; } public void save() { System.out.println("执行目标逻辑前追加功能"); userDao.save(); System.out.println("执行目标逻辑后追加功能"); } }测试
/** * Created by hang on 2018/3/13. */ public class proxyPatternDemo { public static void main(String[] args){ //静态代理执行 UserDaoImp userDaoImp = new UserDaoImp(); UserDaoProxy userDaoProxy = new UserDaoProxy(userDaoImp); userDaoProxy.save(); } }
优点:可以在不修改目标对象的情况下追加新的功能。
缺点:当接口方法中添加新的方法之后,目标对象和代理对象都要进行维护。
动态代理
动态代理技术就是动态的创建类的技术,利用JDK的api动态的在内存中构建了对象。这样代理接口就不需要动实现接口了。态代理技术又分为两种一种是JDK动态代理另外一种是cglib动态代理。
1.JDK动态代理
基于接口技术(java.long.reflect.Proxy)实现接口,重写接口中的方法。这种方式目标对象一定要实现接口否则需不能使用这种方式。要使用newProxyInstance()方法。该方法需要传入三个参数。
static Object newProxyInstance(ClassLoader loader,Class>[] interfaces,InvocationHandler h)
loader:是类加载器,用于获取当前目标对象使用的类加载器。
interfaces:是目标对象实现的接口的类型。
h:当执行目标方法时会触发时间处理器的方法。会把当前执行目标对象的方法作为参数传入。
代码实现:
首先还是要先写一个接口和实现类。我这里还是使用的上面的UserDao和UserDaoImp,不用做任何修改。再增加一个代理工厂类。
/** * JDK动态代理 * Created by hang on 2018/3/13. */ public class ProxyFactory { private Object target; public ProxyFactory(Object target){ this.target = target; } public Object getProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理开始事物"); Object returnValue = method.invoke(target,args); System.out.println("JDK动态代理提交事物"); return returnValue; } }); } }
测试类:
/** * Created by hang on 2018/3/13. */ public class proxyPatternDemo { public static void main(String[] args){ //JDK动态代理执行 UserDaoImp userDaoImp = new UserDaoImp(); System.out.println(userDaoImp.getClass()); //给目标对象创建代理对象 UserDao proxy = (UserDao) new ProxyFactory(userDaoImp).getProxyInstance(); System.out.println(proxy.getClass()); proxy.save(); } }cglib代理:
这种代理方式是为了解决目标对象并没有实现任何接口的时候可以使用这种方式生成一个子类对象从而实现对目标对象功能的扩展所以这张方式也叫做子类代理。
cglib是一个强打的高性能的代码生成包,它可以在运行期扩展java类与java接口。所有被广泛的使用在许多AOP的框架中。cglib包的底层是通过使用一小块字节码处理框架ASM来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件格式和指令集都很熟悉。
实现:
1.引入cglib的jar包,Spring的核心包中已经包括了Cglib功能所以直接引入pring-core-3.2.5.jar
即可。
2.代理类不能为final的,否则会报错。
3.目标对象的方法何如是final或static修饰的那么就不会被拦截,也就不会执行目标对象额外的追加的功能。
目标对象:可以直接使用上面写好的UserDaoImp对象。
cglib代理工厂:
/** * 此类是通过spring-cors 实现动态代理 * 1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可. * 2.引入功能包后,就可以在内存中动态构建子类 * 3.代理的类不能为final,否则报错 * 4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法. * Created by hang on 2018/3/13. */ public class SpringCoreProxyFactory implements MethodInterceptor{ private Object target; public SpringCoreProxyFactory(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(); } /** * 这里相当于一个拦截器,再调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截, * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("CGlib动态代理开始事务..."); //执行目标对象的方法 Object returnValue = method.invoke(target, objects); System.out.println("CGlib动态代理提交事务..."); return returnValue; } }
测试代码
/** * 使用junit进行测试需要导入junit的jar包 * Created by hang on 2018/3/13. */ public class SpringCoreTest { @Test public void test(){ //目标对象 SpringCoreUserDaoImp target = new SpringCoreUserDaoImp(); //代理对象 SpringCoreUserDaoImp proxy = (SpringCoreUserDaoImp) new SpringCoreProxyFactory(target).getProxyInstance(); //执行代理对象的方法 proxy.save(); } }