了解代理就要自动什么是代理,代理就是代理你办事的“人”,生活中有许多这样的例子,比如婚介所,中介。
可以让代码更加纯粹,不需要在主要业务代码中加入其他附庸的功能
公共部分交给了代理,实现了业务的分工
公共业务发生扩展的时候,方便集中管理
静态代理由程序员或代码生成工具生成代理类,编译之后生成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();
}
}
测试结果:
是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) {
this.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(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”/
原文:https://www.cnblogs.com/liuzhihui021221/p/14695748.html