Java 代理详解

Java代理模式详解

 

Java 代理详解

       欢迎访问我的个人博客

       Java的世界,框架永远如夜空繁星Java的框架,多如牛毛Spring ,hibernate,ibatis/myBatis, struts1/2,  shiro, lucene等等,有时候会觉得这些框架都非常神奇,解决了很多开发的问题,让开发人员进行系统、服务开发时变得简单,框架内部变得神秘,其实无论什么框架,其实现无非是基于JDK来开发的,反射、代理、泛型、注解、以及各种设计模式是框架的灵魂。比如下图的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected  Object createProxy(
         Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
 
     ProxyFactory proxyFactory =  new  ProxyFactory();
     // Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
     proxyFactory.copyFrom( this );
 
     if  (!shouldProxyTargetClass(beanClass, beanName)) {
         // Must allow for introductions; can't just set interfaces to
         // the target's interfaces only.
         Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass,  this .proxyClassLoader);
         for  (Class<?> targetInterface : targetInterfaces) {
             proxyFactory.addInterface(targetInterface);
         }
     }
 
     Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
     for  (Advisor advisor : advisors) {
         proxyFactory.addAdvisor(advisor);
     }
 
     proxyFactory.setTargetSource(targetSource);
     customizeProxyFactory(proxyFactory);
 
     proxyFactory.setFrozen( this .freezeProxy);
     if  (advisorsPreFiltered()) {
         proxyFactory.setPreFiltered( true );
     }
 
     return  proxyFactory.getProxy( this .proxyClassLoader);
}

 

用的正好是反射机制和代理模式,本文主要讲讲Java的代理模式的思想,以及他的分类和实现方式。

 

    1. 静态代理

      静态代理是代理最简单的一种方式,实现为,一个实现类,一个接口,一个代理类,一个测试类,即可完成静态代 理,举个“栗子”,我们去银行存钱我们没有存钱的能力,需要漂亮的营业员小姐(可能是娘炮的先生)帮我们把钱存到账户里面,我们实际是代理,真正的实现类是营业员小姐,我们在存钱时需要先给钱给营业员,而钱不会自己跑到营业员小姐那里,所以我们是代理类。代码如下

      银行员工接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 
  */
package  cn.inspries.test.proxy;
/* 银行美女
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:07:32
  * ***********************************
  */
public  class  BankBeauty  implements  MoneyManager{
@Override
public  void  putMoney( double  money) {
System.out.println( "您存了"  + money +  "元人民币,请对我的服务进行评价!" );
}
}

客户类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 
  */
package  cn.inspries.test.proxy;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:06:50
  * ***********************************
  */
public  class  Custom  implements  MoneyManager{
     BankBeauty bankBeauty =  new  BankBeauty();
@Override
public  void  putMoney( double  money) {
System.out.println( "去到银行柜台!开始存钱" );
bankBeauty.putMoney(money);
System.out.println( "存好了" );
}
     
}

静态代理接口代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 
  */
package  cn.inspries.test.proxy;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:08:54
  * ***********************************
  */
public  interface  MoneyManager {
void  putMoney( double  money);
}

静态代理测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 
  */
package  cn.inspries.test.proxy;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:26:41
  * ***********************************
  */
public  class  Test {
public  static  void  main(String[] args) {
Custom custom =  new  Custom();
custom.putMoney( 200.0 );
}
}

输出结果:

    去到银行柜台!开始存钱

    您存了200.0元人民币,请对我的服务进行评价!

    存好了

上面的例子很简单这里就不再多做解释了

  1. 动态代理

    1. JDK动态代理主要使用java.lang.reflect包里面的一系列类去实现,通过实现InvocationHandler 的Object cn.inspries.test.proxy.dynic.DynicProxy.invoke(Object proxy, Methodmethod, Object[] args) throws Throwable 方法,通过这三个参数对对象来进行方法的调用,从而实现动态代理。

    2.  

     接口和实现类跟静态代理一样,代理类有所区别。代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
 
  */
package  cn.inspries.test.proxy.dynic;
 
import  java.lang.reflect.InvocationHandler;
import  java.lang.reflect.Method;
import  java.lang.reflect.Proxy;
 
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:06:50
  * ***********************************
  */
public  class  DynicProxy  implements  InvocationHandler {
     Object targetObject;
 
     public  Object newProxyInstance(Object targetObject) {
         this .targetObject = targetObject;
         return  Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                 targetObject.getClass().getInterfaces(),  this );
     }
 
     @Override
     public  Object invoke(Object proxy, Method method, Object[] args)
             throws  Throwable {
         Object returnObject =  null ;
         try  {
             System.out.println( "调用动态代理方法了!" );
             returnObject = method.invoke(targetObject, args);
         catch  (Exception e) {
             e.printStackTrace();
             throw  e;
         }
         return  returnObject;
     }
 
}

   JDK动态代理测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    /**
 
  */
package  cn.inspries.test.proxy.dynic;
import  cn.inspries.test.proxy.BankBeauty;
import  cn.inspries.test.proxy.MoneyManager;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:26:41
  * ***********************************
  */
public  class  DynicTest {
public  static  void  main(String[] args) {
DynicProxy dynicProxy =  new  DynicProxy();
MoneyManager moneyManager =  (MoneyManager) dynicProxy.newProxyInstance( new  BankBeauty());
moneyManager.putMoney( 2000 );
}
}

输出

调用代理方法了!

您存了2000.0元人民币,请对我的服务进行评价!

      1. Cglib动态代理,JDK动态代理的局限是,被代理的服务类必须实现接口,否则无法使用代理,将会报错,而Spring里面很多地方用的是类,他是通过Cglib来完成无接口的动态代理的。代码也比较简洁如下。

         

Cglib动态代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 
  */
package  cn.inspries.test.proxy.dynic_cglib;
import  java.lang.reflect.Method;
import  org.springframework.cglib.proxy.Enhancer;
import  org.springframework.cglib.proxy.MethodInterceptor;
import  org.springframework.cglib.proxy.MethodProxy;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:06:50
  * ***********************************
  */
public  class  CglibDynicProxy  implements  MethodInterceptor {
Object targetObject;
public  Object newProxyInstance(Object targetObject) {
this .targetObject = targetObject;
Enhancer enhancer =  new  Enhancer();
enhancer.setSuperclass( this .targetObject.getClass());
enhancer.setCallback( this );  // call back method
return  enhancer.create();  // create proxy instance
}
@Override
public  Object intercept(Object target, Method method, Object[] args,
MethodProxy proxy)  throws  Throwable {
System.out.println( "使用cglib的MethodInterceptor.intercept方法调用代理了!" );
Object result = proxy.invokeSuper(target, args);
System.out.println( "方法走完了,哈哈" );
return  result;
}
}

Cglib测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 
  */
package  cn.inspries.test.proxy.dynic_cglib;
import  cn.inspries.test.proxy.BankBeauty;
import  cn.inspries.test.proxy.MoneyManager;
/*
  * ***********************************
  * @author sandy
  * @project cn.inspries.test.proxy
  * @create_date 2014-8-14 下午9:26:41
  * ***********************************
  */
public  class  DynicTest {
public  static  void  main(String[] args) {
  CglibDynicProxy cglibDynicProxy =  new  CglibDynicProxy();
  MoneyManager manager = (MoneyManager) cglibDynicProxy.newProxyInstance( new  BankBeauty());
  manager.putMoney( 1688 );
}
}

 

程序输出:

使用cglib的MethodInterceptor.intercept方法调用代理了!

您存了1688.0元人民币,请对我的服务进行评价!

方法走完了,哈哈

总结:动态代理和静态代理的区别

1、静态代理由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的class文件,代理类和委托类的关系在运行前就确定了。

2、静态代理只服务于一个接口。而动态代理可以服务于多个接口。

3、静态代理中如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

4、动态代理类的代码是在程序运行期间由JVM根据反射等机制动态的生成,不存在代理类的字节码文件。代理类和委托类的关系在程序运行时候确定。

5、动态代理与普通的代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

JDK动态代理方式和CGlib区别是,使用jdk代理是,代理类必须实现接口,而Cglib不论有没有接口都可以实现,所以cglib局限较小。

同步定位与地图构建(SLAM)技术为移动机器人或自主载具在未知空间中的导航提供了核心支撑。借助该技术,机器人能够在探索过程中实时构建环境地图并确定自身位置。典型的SLAM流程涵盖传感器数据采集、数据处理、状态估计及地图生成等环节,其核心挑战在于有效处理定位与环境建模中的各类不确定性。 Matlab作为工程计算与数据可视化领域广泛应用的数学软件,具备丰富的内置函数与专用工具箱,尤其适用于算法开发与仿真验证。在SLAM研究方面,Matlab可用于模拟传感器输出、实现定位建图算法,并进行系统性能评估。其仿真环境能显著降低实验成本,加速算法开发与验证周期。 本次“SLAM-基于Matlab的同步定位与建图仿真实践项目”通过Matlab平台完整再现了SLAM的关键流程,包括数据采集、滤波估计、特征提取、数据关联与地图更新等核心模块。该项目不仅呈现了SLAM技术的实际应用场景,更为机器人导航与自主移动领域的研究人员提供了系统的实践参考。 项目涉及的核心技术要点主要包括:传感器模型(如激光雷达与视觉传感器)的建立与应用、特征匹配与数据关联方法、滤波器设计(如扩展卡尔曼滤波与粒子滤波)、图优化框架(如GTSAM与Ceres Solver)以及路径规划与避障策略。通过项目实践,参与者可深入掌握SLAM算法的实现原理,并提升相关算法的设计与调试能力。 该项目同时注重理论向工程实践的转化,为机器人技术领域的学习者提供了宝贵的实操经验。Matlab仿真环境将复杂的技术问题可视化与可操作化,显著降低了学习门槛,提升了学习效率与质量。 实践过程中,学习者将直面SLAM技术在实际应用中遇到的典型问题,包括传感器误差补偿、动态环境下的建图定位挑战以及计算资源优化等。这些问题的解决对推动SLAM技术的产业化应用具有重要价值。 SLAM技术在工业自动化、服务机器人、自动驾驶及无人机等领域的应用前景广阔。掌握该项技术不仅有助于提升个人专业能力,也为相关行业的技术发展提供了重要支撑。随着技术进步与应用场景的持续拓展,SLAM技术的重要性将日益凸显。 本实践项目作为综合性学习资源,为机器人技术领域的专业人员提供了深入研习SLAM技术的实践平台。通过Matlab这一高效工具,参与者能够直观理解SLAM的实现过程,掌握关键算法,并将理论知识系统应用于实际工程问题的解决之中。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值