1、静态代理
测试类:
package com.example.demo.proxy;public class StaticProxy implements UserDao { private UserDao userdao; public UserDao getUserdao() { return userdao; } public void setUserdao(UserDao userdao) { this.userdao = userdao; } @Override public void getUser() { System.out.println("代理类进入"); userdao.getUser(); System.out.println("代理类退出"); } public static void main(String[] args) { StaticProxy sp = new StaticProxy(); UserDao userDao = new UserDaoImpl(); sp.setUserdao(userDao); sp.getUser(); }}
userdao:
package com.example.demo.proxy;public interface UserDao { void getUser();}
userdaoimpl:
package com.example.demo.proxy;public class UserDaoImpl implements UserDao { @Override public void getUser() { System.out.println("userdao impl"); }}
运行测试类:
代理类进入userdao impl代理类退出
2、jdk动态代理
测试类:package com.example.demo.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class DynamicProxy1 { //维护一个被代理的类 private Object obj; public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public Object getInstance() { return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入proxy"); //invoke两个参数,obj原对象,args参数 method.invoke(obj, args); System.out.println("退出proxy"); return null; } }); } public static void main(String[] args) { DynamicProxy1 dp1 = new DynamicProxy1(); dp1.setObj(new UserDaoImpl()); UserDao instance = (UserDao) dp1.getInstance(); instance.getUser(); }}
userdao和userdaoimpl同上
运行测试类:
进入proxyuserdao impl退出proxy
JDK动态代理局限性
通过反射类Proxy和InvocationHandler回调接口实现的jdk动态代理,要求委托类必须实现一个接口,但事实上并不是所有类都有接口,对于没有实现接口的类,便无法使用该方方式实现动态代理。
3、cglib动态代理
静态代理和jdk动态代理模式都是要求目标对象实现一个接口, Cglib代理,也叫作子类代理,是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk ,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展. 它有如下特点:
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现. Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截) Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
注意 需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可. 引入功能包后,就可以在内存中动态构建子类 代理的类不能为final,否则报错 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
测试类:
package com.example.demo.proxy;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * 实现methodInterceptor方法,并重写interceptor方法 */public class CglibDynamicProxy implements MethodInterceptor { //维护一个被代理的对象 private Object target; public Object getinstance() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); //回调方法指定当前类即可(实现了methodInterceptor接口的类) enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("cglib代理开始"); Object invoke = method.invoke(target, objects); System.out.println("cglib代理结束"); return invoke; } public static void main(String[] args) { CglibDynamicProxy cg = new CglibDynamicProxy(); UserWithoutInterface u = new UserWithoutInterface(); cg.setTarget(u); UserWithoutInterface instance = (UserWithoutInterface) cg.getinstance(); instance.getuser(); } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; }}
被代理对象UserwithoutInterface:
package com.example.demo.proxy;public class UserWithoutInterface { public void getuser(){ System.out.println("执行userwithoutInterface中的getuser方法"); }}
执行测试类结果:
cglib代理开始执行userwithoutInterface中的getuser方法cglib代理结束
参考: