理解
Java 中的动态代理是一种在运行时创建代理对象的机制。动态代理允许程序在运行时决定代理对象的行为,而不需要在编译时确定。它通过代理模式为对象提供了一种机制,使得可以在不修改目标对象的情况下对其行为进行增强或调整。
代理可以看作是调用目标的一个包装,通常用来在调用真实的目标之前进行一些逻辑处理,消除一些重复的代码.。
静态代理指的是我们预先编码好一个代理类,而动态代理指的是运行时生成代理类。
扩展知识
动态代理主要用途
-
- 简化代码:通过代理模式,可以减少重复代码,尤其是在横切关注点(如日志记录、事务管理、权限控制等)方面。
-
- 增强灵活性:动态代理使得代码更具灵活性和可扩展性,因为代理对象是在运行时生成的,可以动态地改变行为。
-
- 实现 AOP:动态代理是实现面向切面编程(AOP,Aspect-Oriented Programming)的基础,可以在方法调用前后插入额外的逻辑。
-
## Java 动态代理与 CGLIB 代理:
-
- Java 动态代理:只能对接口进行代理,不支持对类进行代理。
-
- CGLIB 代理:通过字节码技术动态生成目标类的子类来实现代理,支持对类(非接口)进行代理。
JDK 示例代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 目标接口
interface MyService {
void doSomething();
}
// 目标对象的实现
class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("Doing something...");
}
}
// 动态代理处理器
class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method call");
Object result = method.invoke(target, args);
System.out.println("After method call");
return result;
}
}
// 使用动态代理
public class Main {
public static void main(String[] args) {
MyService target = new MyServiceImpl();
MyService proxy = (MyService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvocationHandler(target)
);
proxy.doSomething();
}
}
CGLIB代码:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 目标类
class MyService {
public void doSomething() {
System.out.println("Doing something...");
}
}
// CGLIB 代理处理器
class MyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before method call");
Object result = proxy.invokeSuper(obj, args);
System.out.println("After method call");
return result;
}
}
// 使用 CGLIB 动态代理
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyService.class);
enhancer.setCallback(new MyInterceptor());
MyService proxy = (MyService) enhancer.create();
proxy.doSomething();
}
}
两种代理的区别:
**JDK动态代理**是基于接口的,所以要求代理类一定是有定义接口的。
**CGLIB**基于 ASM 字节码生成工具,它是通过继承的方式生成目标类的子类来实现代理类,所以要注意 final 方法它们之间的性能随着 JDK 版本的不同而不同。
jdk6 下,在运行次数较少的情况下,jdk动态代理与 caglib 差距不明显,甚至更快一些。而当调用次数增加之后,cglib表现稍微更快一些。
jdk7 下,情况发生了逆转!在运行次数较少(1,000,000)的情况下,jdk动态代理比 cglib 快了差不多
30%;而当调用次数增加之后(50,000,000),动态代理比 cqlib 快了接近1倍。
jdk8 表现和 jdk7 基本一致。
形象理解(打官司)
1、主人公张三首先得明确张三要干嘛:对,他要打官司,去告李四,好,新建接口去告李四
//定义打官司接口
interface Service{
void gan();
}
//定义需要被代理实现的类
class ServiceImpl implements Service{
@Override
public void gan() {
System.out.println("我要告李四!");
}
}
2、接下来去找律师,java动态代理呢你就只能找法院安排好的律师和他们商量怎么干
public class ServiceInvocationHandle implements InvocationHandler {
//定义给律师的目标,你得给律师具体安排的活,干李四
private final Object target;
public ServiceInvocationHandle(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//准备好文件,目标是干李四,args怎么干
Object result = method.invoke(target,args);
System.out.println("开干,奥里给!");
return result;
}
}
3、到法院找到律师,找律师前得注意你要干李四因为啥,才好找啥样的律师而不是一股脑都去找仲裁
public static void main(String[] args) {
//把昨晚起草好的文件带上
Service target = new ServiceImpl();
Service proxy = (Service) Proxy.newProxyInstance(
//法院根据你得文件给你定位问题
target.getClass().getClassLoader(),
//法院根据你得问题给你分类(仲裁、离婚、分财产)
target.getClass().getInterfaces(),
//法院根据你得问题类别给你找相应的律师
new ServiceInvocationHandle(target)
);
//律师猛干,拿下李四
proxy.gan();
}
总结:
**通过InvocationHandler 得到切面;再通过Proxy根据目标类、接口、切面类得到相应的代理类;最后通过切面类的invoke方法,根据反射获取目标类的属性方法去操作。**
CGLIB理解相似但是技术不同java动态通过反射,CGLIB通过字节码。所以CGLIB是通过继承,不需要接口来操作,操作大同小异
标签:Java,target,Object,代理,proxy,动态,public From: https://blog.csdn.net/cgk_ALEM/article/details/144020695import net.sf.cglib.proxy.Enhancer;
public class CglibDynamicProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Service.class);
enhancer.setCallback(new ServiceMethodInterceptor());
Service proxy = (Service) enhancer.create();
proxy.perform();
}
}