Java静态代理和动态代理
静态代理
package com.liuliu.spring.service;
/**
* 静态代理的实现步骤描述:
*
* 定义目标接口:创建一个接口,包含需要被代理的方法。
*
* 实现真实对象:实现该接口的具体类,包含实际的业务逻辑。
*
* 创建代理类:创建一个代理类,同样实现目标接口,持有对真实对象的引用,并在方法中添加额外的逻辑。
*
* 使用代理类:在主程序中,实例化真实对象和代理对象,通过代理对象调用方法,从而实现对真实对象方法的增强。
*/
public class StaticProxy {
public static void main(String[] args) {
MyService3 realService = new MyServiceImpl3();
MyService3 proxyService = new MyServiceProxy(realService);
// 调用代理方法
int result = proxyService.performAction(5);
System.out.println("Result: " + result);
}
}
// 抽象主题(Subject)接口
interface MyService3 {
int performAction(int value);
}
// 真实主题(Real Subject)
class MyServiceImpl3 implements MyService3 {
@Override
public int performAction(int value) {
System.out.println("Action performed with value: " + value);
return value * 3; // 示例:返回值为参数的两倍
}
}
// 代理类
class MyServiceProxy implements MyService3 {
// 抽象主题接口的引用
private final MyService3 realService;
public MyServiceProxy(MyService3 realService) {
this.realService = realService;
}
@Override
public int performAction(int value) {
System.out.println("Before method call");
// 调用真实主题的方法并获取返回值
int result = realService.performAction(value);
System.out.println("After method call");
// 返回结果
return result;
}
}
JDK动态代理
package com.liuliu.spring.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 具体实现
* 代理模式涉及以下几个角色:
* <p>
* 抽象主题(Subject):是一个接口或抽象类,定义了真实主题和代理对象共同实现的方法,客户端通过抽象主题访问真实主题。
* 真实主题(Real Subject):是真正执行业务逻辑的对象,实现了抽象主题定义的方法,是代理模式中被代理的对象。
* 代理(Proxy):持有对真实主题的引用,可以控制对真实主题的访问,在其自身的方法中可以调用真实主题的方法,同时也可以在调用前后执行一些附加操作。
* ————————————————
*
* JDK 动态代理的实现步骤主要包括以下几个步骤:
* 引入 JDK 动态代理支持:确保你的项目中使用 Java 反射机制。
* 定义接口:创建一个接口,包含要代理的方法。
* 实现真实类:创建一个实现上述接口的真实类,定义具体的业务逻辑。
* 实现 InvocationHandler:通过实现 InvocationHandler 接口来定义增强逻辑,重写 invoke() 方法。
* 创建代理实例:使用 Proxy 类的 newProxyInstance() 方法,指定类加载器、接口和 InvocationHandler 实现,创建代理对象
*/
public class JDKProxy {
public static void main(String[] args) {
MyService realService = new MyServiceImpl();
// 创建代理实例
MyService proxyService = (MyService) Proxy.newProxyInstance(
MyService.class.getClassLoader(), // 类的加载器
new Class<?>[]{MyService.class}, // 抽象主题接口
new MyInvocationHandler(realService) // 真实主题
);
// 调用代理方法
int result = proxyService.performAction(5);
System.out.println("Result: " + result);
}
}
// 抽象主题(Subject)接口
interface MyService {
int performAction(int value);
}
// 真实主题(Real Subject)
class MyServiceImpl implements MyService {
@Override
public int performAction(int value) {
System.out.println("Action performed with value: " + value);
return value * 2; // 示例:返回值为参数的两倍
}
}
// 代理(Proxy)
class MyInvocationHandler implements InvocationHandler {
/**
* 表示真实被代理的对象 MyServiceImpl
*/
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
/**
* @param proxy 就是调用该方法的对象(由Proxy.newProxyInstance返回的代理实例)
* @param method 相当于被代理类的方法:比如performAction(int value)
* @param args 被代理类方法传递的参数:比如performAction(5)
* @return 一般返回方法的返回值,如果返回null,就空指针异常??
* @throws Throwable
*/
@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;
}
}
Cglib动态代理
package com.liuliu.spring.service;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* CGLIB 动态代理的实现过程主要包括以下几个步骤:
* <p>
* 引入 CGLIB:确保你在项目中添加了 CGLIB 的依赖。
* 定义真实类:创建要代理的真实类。(不需要抽象类)
* 实现 MethodInterceptor:通过实现 MethodInterceptor 接口来定义增强逻辑(通过重写方法intercept())。
* 使用 Enhancer 创建代理:通过 Enhancer 类设置父类和回调,然后创建代理实例。
*/
public class CglibProxy {
public static void main(String[] args) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyServiceImpl2.class); // 设置父类为 MyServiceImpl2
enhancer.setCallback(new MyMethodInterceptor()); // 设置方法拦截器
// 创建代理实例
MyServiceImpl2 proxyService = (MyServiceImpl2) enhancer.create();
// 调用代理方法
int result = proxyService.performAction(5);
System.out.println("Result: " + result);
}
}
// 真实主题(Real Subject)
class MyServiceImpl2 {
public int performAction(int value) {
System.out.println("Action performed with value: " + value);
return value * 2; // 示例:返回值为参数的两倍
}
}
// 代理(Proxy)
class MyMethodInterceptor implements MethodInterceptor {
/**
* @param obj 传入的是代理实例 proxyService,即 MyServiceImpl2。
* @param method 传入的是被调用的 performAction 方法的 Method 对象。
* @param args 传入的是调用 performAction 时提供的参数数组,这里是一个包含值 5 的数组,即 new Object[]{5}。
* @param proxy 传入的是 CGLIB 的 MethodProxy 对象,用于调用真实的 performAction 方法。
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object obj, java.lang.reflect.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;
}
}
静态代理、JDK动态代理和CGLIB动态代理的区别
特性 | 静态代理 | JDK动态代理 | CGLIB动态代理 |
---|---|---|---|
定义 | 编译时生成代理类 | 运行时通过反射生成代理类 | 运行时通过字节码生成代理类 |
实现方式 | 手动实现代理接口 | 依赖Java接口 | 通过继承被代理类 |
优点 | 简单直观,易于理解 | 代码量少,灵活性高 | 可以代理没有接口的类,性能较好 |
缺点 | 增加代码量,维护复杂 | 只能代理实现接口的类 | 不能代理final类或final方法 |
性能 | 较好 | 较低(因使用反射) | 较好 |
适用场景 | 简单或固定的代理需求 | 大部分动态代理情境 | 需要代理没有接口的类或所有方法 |
选择建议
- 实现接口:选择JDK动态代理。
- 无接口:选择CGLIB动态代理。
- 简单需求:考虑静态代理。
Spirng中的动态代理的场景:
-
Spring AOP 默认使用 JDK 动态代理,如果被代理的类实现了接口。
-
如果目标类没有实现任何接口,或者你强制要求使用 CGLIB 代理,可以通过配置来指定。
<aop:aspectj-autoproxy proxy-target-class="true" />