静态代理和动态代理原理及实现
一,静态代理
静态代理要先抽象出一个接口,并且写一个实现类实现这个接口。
//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{
public String first() {
// TODO Auto-generated method stub
return "I Love You";
}
public String second() {
// TODO Auto-generated method stub
return "China";
}
}
然后写静态代理类,要求静态代理类要求目标类共同实现主业务接口 。这里的代理类实现的是把目标类的某些方法的返回值变成大写。
public class SomeServiceProxy implements SomeService{
private SomeService target;
//提供无参构造器和带参构造器传递方法
public SomeServiceProxy(){
super();
}
public SomeServiceProxy(SomeService target) {
super();
this.target = target;
}
public String first() {
// TODO Auto-generated method stub
return target.first();//正常输出
}
public String second() {
// TODO Auto-generated method stub
return target.second().toUpperCase();//变大写
}
}
写一个测试类
public class MyTest {
public static void main(String args[]){
//定义目标对象
SomeService target=new SomeServiceImpl();
//定义目标对象的代理对象,把目标对象传进去
SomeService serviceProxy=new SomeServiceProxy(target);
String result1=serviceProxy.first();
String result2=serviceProxy.second();
System.out.println(result1+","+result2);
}
}
执行结果
执行了代理类之后,second方法的返回值变成了大写。
二,jdk动态代理
首先jdk动态代理和静态代理一样,都需要先抽象出来一个接口并实现这个接口。
//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{
public String first() {
// TODO Auto-generated method stub
return "I Love You";
}
public String second() {
// TODO Auto-generated method stub
return "China";
}
}
然后写测试类,动态代理在测试类中创建(Proxy类的newProxyInstance方法)
public class MyTest {
public static void main(String args[]){
//定义目标对象
final SomeService target=new SomeServiceImpl();
//定义目标对象的代理对象
SomeService serviceProxy=(SomeService)Proxy.newProxyInstance(
target.getClass().getClassLoader(),//第一个参数:目标类的类加载器
target.getClass().getInterfaces(),//第二个参数:目标类所实现的所有接口
new InvocationHandler() { //第三个参数:内部匿名类
/**
* 增强就在这里完成
* proxy:代理对象
* method:目标方法
* args:目标方法的参数列表
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 内部类使用外部类的成员变量,外部类的成员变量必须声明为final类型,否则报错
Object result = method.invoke(target, args);
//指定操作的是哪个方法
if ("second".equals(method.getName())) {
result = ((String) result).toUpperCase();
}
return result;
}
});
String result1=serviceProxy.first();
String result2=serviceProxy.second();
System.out.println(result1+","+result2);
}
}
执行结果
second方法的返回值也变成了大写。
1,JDK动态代理小例子
一个小汽车,有一个跑run()的方法,我们想使用jdk动态代理使小汽车执行run之前 加点油,run之后洗车。有四个类,接口Car(小汽车)Kayan(具体实现类(卡宴)) CarProxy(汽车的代理) Test(测试类)
Car
public interface Car {
public void run();
}
Kayan这个是小汽车实现类
public class Kayan implements Car {
@Override
public void run() {
System.out.println("小汽车开始跑。。。。。。。。");
}
}
CarProxy 小汽车的代理类
public class CarProxy implements InvocationHandler {
// 小汽车会被代理
private Car car;
// 通过set传入小汽车
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Car creatCarProxy() {
Car proxy = (Car) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("run".equals(method.getName())) {
// 小汽车想要跑之前那要先加油啊
System.out.println("给小汽车加油啊。。oil。。oil。。oil");
Object object = method.invoke(car, args);
System.out.println("跑完之后给小汽车擦车啊。。clean。。clean");
return object;
}
return method.invoke(car, args);
}
}
测试代码
// 测试小汽车的代理
@Test
public void testCarProxy() {
Car ky = new Kayan();
CarProxy proxy = new CarProxy();
proxy.setCar(ky);
Car carProxy = proxy.creatCarProxy();
carProxy.run();
}
最后的结果显示
这种实现的思想类似于Spring的Aop的实现思路,但是AOP在使用jdk动态代理的时候也是用CGLib代理 。
三,CGLIB动态代理
使用JDK的Proxy实现代理,要求目标类和代理类实现相同的接口,若目标类不存在接口,则无法使用该方式实现。对于无接口的类,要为其创建动态代理,就要使用CGLIB实现。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。
所以,使用CGLIB动态代理,要求目标类必须能够被继承,即不能是final的类。
CGLIB是一个外部项目,首先要导入jar包
这里不需要抽象一个接口,只写一个主业务类。
//主业务类
public class SomeService {
public String first() {
// TODO Auto-generated method stub
return "I Love You";
}
public String second() {
// TODO Auto-generated method stub
return "China";
}
}
然后写一个CGLIB动态代理创建工厂
//要实现MethodInterceptor方法,返回的类型是回调函数,所以cglib_ProxyFactory 类本身也为回调函数对象
public class cglib_ProxyFactory implements MethodInterceptor{
private SomeService target;
public cglib_ProxyFactory() {
super();
// TODO Auto-generated constructor stub
}
public cglib_ProxyFactory(SomeService target) {
super();
this.target = target;
}
//用于创建cglib代理对象
public SomeService myProxyCreator(){
//增强器
Enhancer enhancer=new Enhancer();
//指定父类,即要增强的目标类
enhancer.setSuperclass(SomeService.class);
//指定回调函数对象
enhancer.setCallback(this);
//创建cglib代理对象
return (SomeService) enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
Object result = method.invoke(target, args);
if ("second".equals(method.getName())) {
result = ((String) result).toUpperCase();
}
return result;
}
}
再写一个测试类
public class MyTest {
public static void main(String args[]){
//定义目标对象
final SomeService target=new SomeService();
//定义目标对象的代理对象
SomeService serviceProxy=new cglib_ProxyFactory(target).myProxyCreator();
String result1=serviceProxy.first();
String result2=serviceProxy.second();
System.out.println(result1+","+result2);
}
}
执行结果
second方法的返回值也变成了大写。
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~