Spring 静态代理与动态代理spring动态代理
Spring06: 静态与动态代理
什么是代理
了解代理就要自动什么是代理,代理就是代理你办事的“人”,生活中有许多这样的例子,比如婚介所,中介。
代理有什么好处
可以让代码更加纯粹,不需要在主要业务代码中加入其他附庸的功能
公共部分交给了代理,实现了业务的分工
公共业务发生扩展的时候,方便集中管理
静态代理
静态代理由程序员或代码生成工具生成代理类,编译之后生成Class文件,代理关系在编译期就已经绑定,一个代理关系是一个代理类对应一个基础接口。
角色分析
1、抽象角色:一般使用接口或抽象类
2、真实角色:被代理的角色
3、代理角色:代理真实角色,代理真实角色后,我们会做一些附属操作
4、客户角色:访问代理对象的人
代码实现
1.抽象角色(租房)
package com.znsd.spring.test; public interface Rent { void rentOut(); }2.真实角色(房东)
package com.znsd.spring.test; public class Host implements Rent{ @Override public void rentOut() { // TODO Auto-generated method stub System.out.println("房东要出租房屋"); } }3.代理角色(房屋中介)
package com.znsd.spring.test; public class Agency implements Rent{ Host host = new Host(); @Override public void rentOut() { // TODO Auto-generated method stub host.rentOut(); // 房东的额外操作 fee(); contract(); see(); } public void fee() { System.out.println("收佣金"); } public void contract() { System.out.println("签合同"); } public void see() { System.out.println("看房"); } }4.客户角色(需要租房的人)
package com.znsd.spring.test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; class Dynamic { @Test void test() { Rent rent = new Agency(); rent.rentOut(); } }测试结果:
动态代理
jdk动态代理
是JDK1.3中引入的特性,核心API是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。它利用反射机制在运行时生成代理类的字节码,为Java平台在带来了运行时动态扩展对象行为的能力。其代理关系是在程序运行时期确定得。(必须使用接口)
接口
package com.znsd.spring.dynamicProxy; public interface UserService { void add(int id); void delete(int id); void update(int id); void query(int id); }被代理类
package com.znsd.spring.dynamicProxy; public class UserServiceImpl implements UserService{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { = name; } @Override public void add(int id) { // TODO Auto-generated method stub System.out.println("增加"); } @Override public void delete(int id) { // TODO Auto-generated method stub System.out.println("删除"); } @Override public void update(int id) { // TODO Auto-generated method stub System.out.println("修改"); } @Override public void query(int id) { // TODO Auto-generated method stub System.out.println("查询"); } }增强类
package com.znsd.spring.dynamicProxy; public class Extend { public static void log(String msg,int id) { System.out.println(msg+"了id为:"+id+"的用户"); } }生成被代理类
package com.znsd.spring.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler{ private Object object; public ProxyInvocationHandler() { super(); } public ProxyInvocationHandler(Object object) { super(); this.object = object; } public void setObject(Object object) { this.object = object; } public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object rusObject = method.invoke(object, args); Extend.log(method.getName(), (int)args[0]); return rusObject; } }代理程序控制器
package com.znsd.spring.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler{ private Object object; public ProxyInvocationHandler() { super(); } public ProxyInvocationHandler(Object object) { super(); this.object = object; } public void setObject(Object object) { this.object = object; } public Object getProxy() { // 生成被代理类 return Proxy.newProxyInstance(this.getClass().getClassLoader(), object.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object rusObject = method.invoke(object, args); Extend.log(method.getName(), (int)args[0]); return rusObject; } }使用测试
package com.znsd.spring.dynamicProxy; public class Main { public static void main(String[] args) { ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(new UserServiceImpl()); UserService userService = (UserService)proxyInvocationHandler.getProxy(); userService.add(1); userService.delete(2); userService.update(3); userService.query(4); } }cglib动态代理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
CGLIB动态代理的实现机制是生成目标类的子类,在子类中调用父类的方法从而实现对目标父类方法的增强。
被代理类:
package com.znsd.spring.cglib; public class Tatger { public void save() { System.out.println("正在保存"); } }代理程序控制类:
package com.znsd.spring.cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { // TODO Auto-generated method stub MyLog.befor(); Object obj = arg3.invokeSuper(arg0, arg2); MyLog.end(); return obj; } }增强类:
package com.znsd.spring.cglib; import java.io.Console; public class MyLog { public static void befor() { System.out.println("前置Log"); } public static void end() { System.out.println("后置Log"); } }生成代理类:
package com.znsd.spring.cglib; import org.springframework.cglib.proxy.Enhancer; public class CglibProxy { public static Object getProxy(Class clazz) { // 创建动态代理增强类 Enhancer enhancer = new Enhancer(); // 设置类加载器 enhancer.setClassLoader(clazz.getClassLoader()); // 设置被代理类 enhancer.setSuperclass(clazz); // 设置方法拦截器 enhancer.setCallback(new MyMethodInterceptor()); return enhancer.create(); } }测试:
package com.znsd.spring.cglib; import static org.junit.jupiter.api.Assertions.*; class Test { @org.junit.jupiter.api.Test void test() { Tatger tatger = (Tatger) CglibProxy.getProxy(Tatger.class); tatger.save(); } }两种动态代理的区别
1、Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理
2、 Cglib动态代理:利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理
什么时候用cglib什么时候用jdk动态代理?
1、目标对象生成了接口 默认用JDK动态代理
2、如果目标对象使用了接口,可以强制使用cglib
3、如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换
JDK动态代理和cglib字节码生成的区别?
1、JDK动态代理只能对实现了接口的类生成代理,而不能针对类
2、Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的
Cglib比JDK快?
1、cglib底层是ASM字节码生成框架,但是字节码技术生成代理类,在JDL1.6之前比使用java反射的效率要高
2、在jdk6之后逐步对JDK动态代理进行了优化,在调用次数比较少时效率高于cglib代理效率
3、只有在大量调用的时候cglib的效率高,但是在1.8的时候JDK的效率已高于cglib
4、Cglib不能对声明final的方法进行代理,因为cglib是动态生成代理对象,final关键字修饰的类不可变只能被引用不能被修改
Spring如何选择是用JDK还是cglib?
1、当bean实现接口时,会用JDK代理模式
2、当bean没有实现接口,用cglib实现
3、可以强制使用cglib(在spring配置中加入<aop:aspectj-autoproxy proxyt-target-class=”true”/