- 浏览: 144605 次
- 性别:
- 来自: 上海
-
最新评论
-
lijingshou:
有经验的同学根据自己的情况选一点学习就可以了..当然不叫你从头 ...
java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器! -
rex0654335:
博主之前说的看完月薪两三万,改掉了?没底气了?
java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器! -
lk557:
stinge 写道广告贴??看完之后感觉是广告么?
java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器! -
stinge:
广告贴??
java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器! -
yixiandave:
lk557 写道yixiandave 写道Struts2已经开 ...
java学习者的福音----最强JAVA学习线路图以及各阶段配备的学习神器!
学习Spring必学的Java基础知识(2)----动态代理
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”。以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助。):
[1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081
[2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293
[3] 属性编辑器,即PropertyEditor-->Spring IoC:http://www.iteye.com/topic/1123628
[4] XML基础知识-->Spring配置:http://www.iteye.com/topic/1123630
[5] 注解-->Spring配置:http://www.iteye.com/topic/1123823
[6] 线程本地变更,即ThreadLocal-->Spring事务管理:http://www.iteye.com/topic/1123824
[7] 事务基础知识-->Spring事务管理:http://www.iteye.com/topic/1124043
[8] 国际化信息-->MVC:http://www.iteye.com/topic/1124044
[9] HTTP请求报文-->MVC
Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习。Spring AOP使用了两种代理机制:一种是基于JDK的动态代理;另一种是基于CGLib的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。
带有横切逻辑的实例
我们通过具体化代码实现上一节所介绍例子的性能监视横切逻辑,并通过动态代理技术对此进行改造。在调用每一个目标类方法时启动方法的性能监视,在目标类方法调用完成时记录方法的花费时间。
代码清单6-2 ForumService:包含性能监视横切代码
- packagecom.baobaotao.proxy;
- publicclassForumServiceImplimplementsForumService{
- publicvoidremoveTopic(inttopicId){
- //①-1开始对该方法进行性能监视
- PerformanceMonitor.begin(
- "com.baobaotao.proxy.ForumServiceImpl.removeTopic");
- System.out.println("模拟删除Topic记录:"+topicId);
- try{
- Thread.currentThread().sleep(20);
- }catch(Exceptione){
- thrownewRuntimeException(e);
- }
- //①-2结束对该方法进行性能监视
- PerformanceMonitor.end();
- }
- publicvoidremoveForum(intforumId){
- //②-1开始对该方法进行性能监视
- PerformanceMonitor.begin(
- "com.baobaotao.proxy.ForumServiceImpl.removeForum");
- System.out.println("模拟删除Forum记录:"+forumId);
- try{
- Thread.currentThread().sleep(40);
- }catch(Exceptione){
- thrownewRuntimeException(e);
- }
- //②-2结束对该方法进行性能监视
- PerformanceMonitor.end();
- }
- }
package com.baobaotao.proxy; public class ForumServiceImpl implements ForumService { public void removeTopic(int topicId) { //①-1开始对该方法进行性能监视 PerformanceMonitor.begin( "com.baobaotao.proxy.ForumServiceImpl. removeTopic"); System.out.println("模拟删除Topic记录:"+topicId); try { Thread.currentThread().sleep(20); } catch (Exception e) { throw new RuntimeException(e); } //①-2结束对该方法进行性能监视 PerformanceMonitor.end(); } public void removeForum(int forumId) { //②-1开始对该方法进行性能监视 PerformanceMonitor.begin( "com.baobaotao.proxy.ForumServiceImpl. removeForum"); System.out.println("模拟删除Forum记录:"+forumId); try { Thread.currentThread().sleep(40); } catch (Exception e) { throw new RuntimeException(e); } //②-2结束对该方法进行性能监视 PerformanceMonitor.end(); } }
代码清单6-2中粗体表示的代码就是具有横切逻辑特征的代码,每个Service类和每个业务方法体的前后都执行相同的代码逻辑:方法调用前启动PerformanceMonitor,方法调用后通知PerformanceMonitor结束性能监视并给记录性能监视结果。
PerformanceMonitor是性能监视的实现类,我们给出一个非常简单的实现版本,其代码如代码清单6-3所示:
代码清单6-3 PerformanceMonitor
- packagecom.baobaotao.proxy;
- publicclassPerformanceMonitor{
- //①通过一个ThreadLocal保存调用线程相关的性能监视信息
- privatestaticThreadLocal<MethodPerformace>performanceRecord=
- newThreadLocal<MethodPerformance>();
- //②启动对某一目标方法的性能监视
- publicstaticvoidbegin(Stringmethod){
- System.out.println("beginmonitor...");
- MethodPerformancemp=newMethodPerformance(method);
- performanceRecord.set(mp);
- }
- publicstaticvoidend(){
- System.out.println("endmonitor...");
- MethodPerformancemp=performanceRecord.get();
- //③打印出方法性能监视的结果信息。
- mp.printPerformance();
- }
- }
package com.baobaotao.proxy; public class PerformanceMonitor { //①通过一个ThreadLocal保存调用线程相关的性能监视信息 private static ThreadLocal<MethodPerformace> performanceRecord = new ThreadLocal<MethodPerformance>(); //②启动对某一目标方法的性能监视 public static void begin(String method) { System.out.println("begin monitor..."); MethodPerformance mp = new MethodPerformance(method); performanceRecord.set(mp); } public static void end() { System.out.println("end monitor..."); MethodPerformance mp = performanceRecord.get(); //③打印出方法性能监视的结果信息。 mp.printPerformance(); } }
ThreadLocal是将非线程安全类改造为线程安全类的法宝,在9.2节中我们将详细介绍这个Java基础知识。PerformanceMonitor提供了两个方法:通过调用begin(String method)方法开始对某个目标类方法的监视,method为目标类方法的全限定名;而end()方法结束对目标类方法的监视,并给出性能监视的信息。这两个方法必须配套使用。
用于记录性能监视信息的MethodPerformance类的代码如所示:
代码清单6-4 MethodPerformance
- packagecom.baobaotao.proxy;
- publicclassMethodPerformance{
- privatelongbegin;
- privatelongend;
- privateStringserviceMethod;
- publicMethodPerformance(StringserviceMethod){
- this.serviceMethod=serviceMethod;
- //①记录目标类方法开始执行点的系统时间
- this.begin=System.currentTimeMillis();
- }
- publicvoidprintPerformance(){
- //②获取目标类方法执行完成后的系统时间,并进而计算出目标类方法执行时间
- end=System.currentTimeMillis();
- longelapse=end-begin;
- //③报告目标类方法的执行时间
- System.out.println(serviceMethod+"花费"+elapse+"毫秒。");
- }
- }
package com.baobaotao.proxy; public class MethodPerformance { private long begin; private long end; private String serviceMethod; public MethodPerformance(String serviceMethod){ this.serviceMethod = serviceMethod; //①记录目标类方法开始执行点的系统时间 this.begin = System.currentTimeMillis(); } public void printPerformance(){ //②获取目标类方法执行完成后的系统时间,并进而计算出目标类方法执行时间 end = System.currentTimeMillis(); long elapse = end - begin; //③报告目标类方法的执行时间 System.out.println(serviceMethod+"花费"+elapse+"毫秒。"); } }
通过下面的代码测试拥有性能监视能力的ForumServiceImpl业务方法:
- packagecom.baobaotao.proxy;
- publicclassTestForumService{
- publicstaticvoidmain(String[]args){
- ForumServiceforumService=newForumServiceImpl();
- forumService.removeForum(10);
- forumService.removeTopic(1012);
- }
- }
package com.baobaotao.proxy; public class TestForumService { public static void main(String[] args) { ForumService forumService = new ForumServiceImpl(); forumService .removeForum(10); forumService .removeTopic(1012); } }
我们得到以下输出信息:
模拟删除Forum记录:10
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。
begin monitor... ①removeTopic(1012)方法的性能监视报告
模拟删除Topic记录:1012
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。
正如代码清单6 2实例所示,当某个方法需要进行性能监视,就必须调整方法代码,在方法体前后分别添加上开启性能监视和结束性能监视的代码。这些非业务逻辑的性能监视代码破坏了ForumServiceImpl业务逻辑的纯粹性。我们希望通过代理的方式,将业务类方法中开启和结束性能监视的这些横切代码从业务类中完全移除。并通过JDK动态代理技术或CGLib动态代理技术将横切代码动态织入到目标方法的相应位置。
JDK动态代理
JDK 1.3以后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在我们终于发现动态代理是实现AOP的绝好底层技术。
JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。这样讲一定很抽象,我们马上着手使用Proxy和InvocationHandler这两个魔法戒对上一节中的性能监视代码进行革新。
首先,我们从业务类ForumServiceImpl中删除性能监视的横切代码,使ForumServiceImpl只负责具体的业务逻辑,如代码清单6-5所示:
代码清单6-5 ForumServiceImpl:移除性能监视横切代码
- packagecom.baobaotao.proxy;
- publicclassForumServiceImplimplementsForumService{
- publicvoidremoveTopic(inttopicId){
- ①
- System.out.println("模拟删除Topic记录:"+topicId);
- try{
- Thread.currentThread().sleep(20);
- }catch(Exceptione){
- thrownewRuntimeException(e);
- }
- ①
- }
- publicvoidremoveForum(intforumId){
- ②
- System.out.println("模拟删除Forum记录:"+forumId);
- try{
- Thread.currentThread().sleep(40);
- }catch(Exceptione){
- thrownewRuntimeException(e);
- }
- ②
- }
- }
package com.baobaotao.proxy; public class ForumServiceImpl implements ForumService { public void removeTopic(int topicId) { ① System.out.println("模拟删除Topic记录:"+topicId); try { Thread.currentThread().sleep(20); } catch (Exception e) { throw new RuntimeException(e); } ① } public void removeForum(int forumId) { ② System.out.println("模拟删除Forum记录:"+forumId); try { Thread.currentThread().sleep(40); } catch (Exception e) { throw new RuntimeException(e); } ② } }
在代码清单6-5中的①和②处,原来的性能监视代码被移除了,我们只保留了真正的业务逻辑。
从业务类中移除的性能监视横切代码当然不能漂浮在空气中,它还得找到一个安身之所,InvocationHandler就是横切代码的安家乐园,我们将性能监视的代码安置在PerformanceHandler中,如代码清单6-6所示:
- 代码清单6-6PerformanceHandler
- packagecom.baobaotao.proxy;
- importjava.lang.reflect.InvocationHandler;
- importjava.lang.reflect.Method;
- publicclassPerformanceHandlerimplementsInvocationHandler{//①实现InvocationHandler
- privateObjecttarget;
- publicPerformanceHandler(Objecttarget){//②target为目标的业务类
- this.target=target;
- }
- publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)③
- throwsThrowable{
- PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName());③-1
- Objectobj=method.invoke(target,args);//③-2通过反射方法调用业务类的目标方法
- PerformanceMonitor.end();③-1
- returnobj;
- }
- }
代码清单6-6 PerformanceHandler package com.baobaotao.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class PerformanceHandler implements InvocationHandler {//①实现InvocationHandler private Object target; public PerformanceHandler(Object target){ //②target为目标的业务类 this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) ③ throws Throwable { PerformanceMonitor.begin(target.getClass().getName()+"."+ method. getName());③-1 Object obj = method.invoke(target, args);// ③-2通过反射方法调用业务类的目标方法 PerformanceMonitor.end();③-1 return obj; } }
③处invoke()方法中粗体所示部分的代码为性能监视的横切代码,我们发现,横切代码只出现一次,而不是原来那样星洒各处。③-2处的method.invoke()语句通过Java反射机制间接调用目标对象的方法,这样InvocationHandler的invoke()方法就将横切逻辑代码(③-1)和业务类方法的业务逻辑代码(③-2)编织到一起了,所以我们可以将InvocationHandler看成是一个编织器。下面,我们对这段代码做进一步的说明。
首先,我们实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是最终生成的代理实例,一般不会用到;method是被代理目标实例的某个具体方法,通过它可以发起目标实例方法的反射调用;args是通过被代理实例某一个方法的入参,在方法反射调用时使用。
此外,我们在构造函数里通过target传入希望被代理的目标对象,如②处所示,在InvocationHandler接口方法invoke(Object proxy, Method method, Object[] args)里,将目标实例传给method.invoke()方法,调用目标实例的方法,如③所示。
下面,我们通过Proxy结合PerformanceHandler创建ForumService接口的代理实例,如代码清单6-7所示:
代码清单6-7 TestForumService:创建代理实例
- packagecom.baobaotao.proxy;
- importjava.lang.reflect.Proxy;
- publicclassTestForumService{
- publicstaticvoidmain(String[]args){
- //①希望被代理的目标业务类
- ForumServicetarget=newForumServiceImpl();
- //②将目标业务类和横切代码编织到一起
- PerformanceHandlerhandler=newPerformanceHandler(target);
- //③根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例
- ForumServiceproxy=(ForumService)Proxy.newProxyInstance(
- target.getClass().getClassLoader(),
- target.getClass().getInterfaces(),
- handler);
- //④调用代理实例
- proxy.removeForum(10);
- proxy.removeTopic(1012);
- }
- }
package com.baobaotao.proxy; import java.lang.reflect.Proxy; public class TestForumService { public static void main(String[] args) { //①希望被代理的目标业务类 ForumService target = new ForumServiceImpl(); //②将目标业务类和横切代码编织到一起 PerformanceHandler handler = new PerformanceHandler(target); //③根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例 ForumService proxy = (ForumService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); //④调用代理实例 proxy.removeForum(10); proxy.removeTopic(1012); } }
上面的代码完成业务类代码和横切代码的编织工作并生成了代理实例。在②处,我们让PerformanceHandler将性能监视横切逻辑编织到ForumService实例中,然后在③处,通过Proxy的newProxyInstance()静态方法为编织了业务类逻辑和性能监视逻辑的handler创建一个符合ForumService接口的代理实例。该方法的第一个入参为类加载器;第二个入参为创建代理实例所需要实现的一组接口;第三个参数是整合了业务逻辑和横切逻辑的编织器对象。
按照③处的设置方式,这个代理实例实现了目标业务类的所有接口,即Forum ServiceImpl的ForumService接口。这样,我们就可以按照调用ForumService接口实例相同的方式调用代理实例,如④所示。运行以上的代码,输出以下信息:
模拟删除Forum记录:10
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。
begin monitor...
模拟删除Topic记录:1012
end monitor...
com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。
我们发现,程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致,但是在这里,原来分散的横切逻辑代码已经被我们抽取到PerformanceHandler中。当其他业务类(如UserService、SystemService等)的业务方法也需要使用性能监视时,我们只要按照代码清单6-7相似的方式,分别为它们创建代理对象就可以了。下面,我们通过时序图描述通过创建代理对象进行业务方法调用的整体逻辑,以进一步认识代理对象的本质,如图6-3所示。
我们在上图中使用虚线的方式对通过Proxy创建的ForumService代理实例加以凸显,ForumService代理实例内部利用PerformaceHandler整合横切逻辑和业务逻辑。调用者调用代理对象的removeForum()和removeTopic()方法时,上图的内部调用时序清晰地告诉我们实际上所发生的一切。
CGLib动态代理
使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点我们可从Proxy的接口newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)的方法签名中就看得很清楚:第二个入参interfaces就是需要代理实例实现的接口列表。虽然面向接口编程的思想被很多大师级人物(包括Rod Johnson)推崇,但在实际开发中,许多开发者也对此深感困惑:难道对一个简单业务表的操作也需要老老实实地创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和Service实现类)吗?难道不能直接通过实现类构建程序吗?对于这个问题,我们很难给出一个孰好孰劣的准确判断,但我们确实发现有很多不使用接口的项目也取得了非常好的效果(包括大家所熟悉的SpringSide开源项目)。
对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这个空缺。
CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。下面,我们采用CGLib技术,编写一个可以为任何类创建织入性能监视横切逻辑代理对象的代理创建器,如代码清单 6-8所示:
代码清单6-8 CglibProxy
- packagecom.baobaotao.proxy;
- importjava.lang.reflect.Method;
- importnet.sf.cglib.proxy.Enhancer;
- importnet.sf.cglib.proxy.MethodInterceptor;
- importnet.sf.cglib.proxy.MethodProxy;
- publicclassCglibProxyimplementsMethodInterceptor{
- privateEnhancerenhancer=newEnhancer();
- publicObjectgetProxy(Classclazz){
- enhancer.setSuperclass(clazz);//①设置需要创建子类的类
- enhancer.setCallback(this);
- returnenhancer.create();//②通过字节码技术动态创建子类实例
- }
- //③拦截父类所有方法的调用
- publicObjectintercept(Objectobj,Methodmethod,Object[]args,
- MethodProxyproxy)throwsThrowable{
- PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());//③-1
- Objectresult=proxy.invokeSuper(obj,args);③-2
- PerformanceMonitor.end();//③-1通过代理类调用父类中的方法
- returnresult;
- }
- }
package com.baobaotao.proxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { enhancer.setSuperclass(clazz); //① 设置需要创建子类的类 enhancer.setCallback(this); return enhancer.create(); //②通过字节码技术动态创建子类实例 } //③拦截父类所有方法的调用 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { PerformanceMonitor.begin(obj.getClass().getName()+"."+method. getName());//③-1 Object result=proxy.invokeSuper(obj, args); ③-2 PerformanceMonitor.end();//③-1通过代理类调用父类中的方法 return result; } }
在上面代码中,用户可以通过getProxy(Class clazz)为一个类创建动态代理对象,该代理对象通过扩展clazz创建代理对象。在这个代理对象中,我们织入性能监视的横切逻辑(③-1)。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)是CGLib定义的Interceptor接口的方法,它拦截所有目标类方法的调用,obj表示目标类的实例;method为目标类方法的反射对象;args为方法的动态入参;而proxy为代理类实例。
下面,我们通过CglibProxy为ForumServiceImpl类创建代理对象,并测试代理对象的方法,如代码清单6-9所示:
代码清单6-9 TestForumService:测试Cglib创建的代理类
- packagecom.baobaotao.proxy;
- importjava.lang.reflect.Proxy;
- publicclassTestForumService{
- publicstaticvoidmain(String[]args){
- CglibProxyproxy=newCglibProxy();
- ForumServiceImplforumService=①
- (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);
- forumService.removeForum(10);
- forumService.removeTopic(1023);
- }
- }
package com.baobaotao.proxy; import java.lang.reflect.Proxy; public class TestForumService { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); ForumServiceImpl forumService = ① (ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class); forumService.removeForum(10); forumService.removeTopic(1023); } }
在①中,我们通过CglibProxy为ForumServiceImpl动态创建了一个织入性能监视逻辑的代理对象,并调用代理类的业务方法。运行上面的代码,输入以下信息:
模拟删除Forum记录:10
end monitor...
com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeForum花费47毫秒。
begin monitor...
模拟删除Topic记录:1023
end monitor...
com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeTopic花费16毫秒。
观察以上的输出,除了发现两个业务方法中都织入了性能监控的逻辑外,我们还发现代理类的名字是com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0,这个特殊的类就是CGLib为ForumServiceImpl动态创建的子类。
代理知识小结
Spring AOP的底层就是通过使用JDK动态代理或CGLib动态代理技术为目标Bean织入横切逻辑。在这里,我们对前面两节动态创建代理对象作一个小结。
我们虽然通过PerformanceHandler或CglibProxy实现了性能监视横切逻辑的动态织入,但这种实现方式存在三个明显需要改进的地方:
1)目标类的所有方法都添加了性能监视横切逻辑,而有时,这并不是我们所期望的,我们可能只希望对业务类中的某些特定方法添加横切逻辑;
2)我们通过硬编码的方式指定了织入横切逻辑的织入点,即在目标类业务方法的开始和结束前织入代码;
3)我们手工编写代理实例的创建过程,为不同类创建代理时,需要分别编写相应的创建代码,无法做到通用。
以上三个问题,在AOP中占用重要的地位,因为Spring AOP的主要工作就是围绕以上三点展开:Spring AOP通过Pointcut(切点)指定在哪些类的哪些方法上织入横切逻辑,通过Advice(增强)描述横切逻辑和方法的具体织入点(方法前、方法后、方法的两端等)。此外,Spring通过Advisor(切面)将Pointcut和Advice两者组装起来。有了Advisor的信息,Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。
JDK动态代理所创建的代理对象,在JDK 1.3下,性能强差人意。虽然在高版本的JDK中,动态代理对象的性能得到了很大的提高,但是有研究表明,CGLib所创建的动态代理对象的性能依旧比JDK的所创建的代理对象的性能高不少(大概10倍)。但CGLib在创建代理对象时所花费的时间却比JDK动态代理多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,所以比较适合用CGLib动态代理技术,反之适合用JDK动态代理技术。值得一提的是,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final方法进行代理。
相关推荐
【AI】从头到脚详解如何创建部署Azure Web App的OpenAI项目源码
人脸识别项目实战
人工智能-人脸识别代码,采用cnn的架构识别代码
汽车配件制造业企业信息化整体解决方案
短期风速预测模型,IDBO-BiTCN-BiGRU-Multihead-Attention IDBO是,网上复现 评价指标:R方、MAE、MAPE、RMSE 附带测试数据集运行(风速数据) 提示:在MATLAB2024a上测试正常 ,短期风速预测模型; IDBO-BiTCN-BiGRU-Multihead-Attention; 评价指标: R方、MAE、MAPE、RMSE; 复现; 测试数据集; MATLAB 2024a,短期风速预测模型:IDBO-BiTCN-BiGRU-Attention集成模型
手势识别项目实战
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。
相亲交友系统源码 V10.5支持婚恋相亲、媒婆返利、红娘系统、商城系统等等 这款交友系统功能太多了,适合婚恋相亲,还有媒婆婚庆等等支持 PC和 H5还有小程序,可封装红年、APP,里面带安装教程
本资源《单片机也能玩双核之你想不到的C技巧系列——嵌入式实战》涵盖 双核单片机开发、C语言高级技巧、嵌入式系统优化 等核心内容,结合 实战案例与视频教程,帮助开发者深入理解并掌握高效编程技巧。 适用人群: 适合 嵌入式开发工程师、单片机开发者、电子信息相关专业学生,以及希望提升 C语言编程能力 和 嵌入式项目经验 的技术人员。 能学到什么: 双核单片机开发思路,提高并行处理能力。 C语言高级技巧,提升代码优化与执行效率。 嵌入式系统调试方法,掌握实际项目中的调试策略。 实战案例解析,学习如何在实际工程中应用双核技术。 阅读建议: 建议 先学习基础知识,再结合 示例代码与视频教程 进行实操,重点关注 代码优化、调试技巧与双核应用模式,通过实战演练提高嵌入式开发能力。
人脸识别项目源码实战
人脸识别项目源码实战
c语言学习
红外光伏缺陷目标检测模型,YOLOv8模型 基于红外光伏缺陷目标检测数据集训练,做了必要的数据增强处理,以达到缺陷类别间的平衡 可检测大面积热斑,单一热斑,二极管短路和异常低温四类缺陷 测试集指标如图所示 ,核心关键词:红外光伏缺陷目标检测模型; YOLOv8模型; 数据增强处理; 缺陷类别平衡; 大面积热斑; 单一热斑; 二极管短路; 异常低温。,基于YOLOv8的红外光伏缺陷检测模型
基于PLC的自动浇花控制系统 西门子1200PLC博途仿真,提供HMI画面,接线图,IO分配表,演示视频,简单讲解视频 博图15.1及以上版本均可使用 ,核心关键词: PLC自动浇花控制系统; 西门子1200PLC博途仿真; HMI画面; 接线图; IO分配表; 演示视频; 简单讲解视频; 博图15.1及以上版本。,基于PLC的自动浇花系统:西门子1200PLC博途仿真实践教程
在智慧园区建设的浪潮中,一个集高效、安全、便捷于一体的综合解决方案正逐步成为现代园区管理的标配。这一方案旨在解决传统园区面临的智能化水平低、信息孤岛、管理手段落后等痛点,通过信息化平台与智能硬件的深度融合,为园区带来前所未有的变革。 首先,智慧园区综合解决方案以提升园区整体智能化水平为核心,打破了信息孤岛现象。通过构建统一的智能运营中心(IOC),采用1+N模式,即一个智能运营中心集成多个应用系统,实现了园区内各系统的互联互通与数据共享。IOC运营中心如同园区的“智慧大脑”,利用大数据可视化技术,将园区安防、机电设备运行、车辆通行、人员流动、能源能耗等关键信息实时呈现在拼接巨屏上,管理者可直观掌握园区运行状态,实现科学决策。这种“万物互联”的能力不仅消除了系统间的壁垒,还大幅提升了管理效率,让园区管理更加精细化、智能化。 更令人兴奋的是,该方案融入了诸多前沿科技,让智慧园区充满了未来感。例如,利用AI视频分析技术,智慧园区实现了对人脸、车辆、行为的智能识别与追踪,不仅极大提升了安防水平,还能为园区提供精准的人流分析、车辆管理等增值服务。同时,无人机巡查、巡逻机器人等智能设备的加入,让园区安全无死角,管理更轻松。特别是巡逻机器人,不仅能进行360度地面全天候巡检,还能自主绕障、充电,甚至具备火灾预警、空气质量检测等环境感知能力,成为了园区管理的得力助手。此外,通过构建高精度数字孪生系统,将园区现实场景与数字世界完美融合,管理者可借助VR/AR技术进行远程巡检、设备维护等操作,仿佛置身于一个虚拟与现实交织的智慧世界。 最值得关注的是,智慧园区综合解决方案还带来了显著的经济与社会效益。通过优化园区管理流程,实现降本增效。例如,智能库存管理、及时响应采购需求等举措,大幅减少了库存积压与浪费;而设备自动化与远程监控则降低了维修与人力成本。同时,借助大数据分析技术,园区可精准把握产业趋势,优化招商策略,提高入驻企业满意度与营收水平。此外,智慧园区的低碳节能设计,通过能源分析与精细化管理,实现了能耗的显著降低,为园区可持续发展奠定了坚实基础。总之,这一综合解决方案不仅让园区管理变得更加智慧、高效,更为入驻企业与员工带来了更加舒适、便捷的工作与生活环境,是未来园区建设的必然趋势。
大型集团用户画像系统化标准化数字化用户主数据管理项目规划方案
基于STM32的水质 浊度检测仪设计与实现(详细设计说明书+ 10008-基于STM32的水质 浊度检测仪设计与实现(详细设计说明书+原理图PCB工程+源码工程+实物照片) 本次设计是设计一款水质检测设备,实现温度检查、水质检测的功能,将检测到的数据显示到显示器中,并实时记录系统的参数 本次系统需要对温度检测,使用的传感器为DS18B20,通过单总线的方式来完成系统温度检测 使用水质检测模块检查水的质量 通过传感器检测到的数据计算后的值实时刷新到显示器中,主要的功能包括以下几点: ①可以对温度实时检测; ②可以对水质实际值实时检测; ③水质浑浊预警 主要特点: 1.以STM32单片机为核心,配合水质模块; 2.主要完成系统的 功能控制、状态显示、信息检测以及报警硬件组建所单片机和传感器等元器件的选择; 3.完成系统控制的软件设计编程; 4.实现对水质检测、温度检查、预警的功能 内容包含: 1、原理图工程 2、PCB工程 3、源码工程 4、实物照片 5、详细介绍说明书-22531字 6、实物照片 7、浊度传感器资料
人脸识别项目实战
华中科技大学计算机科学研究生复试上机测试题.zip
YOLOv8部署到web上(Django+html)