`

spring的jdk代理个cglib代理

阅读更多

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”。以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助。): 
[1] Java反射知识-->Spring IoC 
[2] 属性编辑器,即PropertyEditor-->Spring IoC 
[3] Java动态代理-->Spring AOP 
[4] 线程本地变更,即ThreadLocal-->Spring事务管理
 


Spring AOP使用动态代理技术在运行期织入增强的代码,为了揭示Spring AOP底层的工作机理,有必要对涉及到的Java知识进行学习。Spring AOP使用了两种代理机制:一种是基于JDK的动态代理;另一种是基于CGLib的动态代理。之所以需要两种代理机制,很大程度上是因为JDK本身只提供接口的代理,而不支持类的代理。 

带有横切逻辑的实例 

我们通过具体化代码实现上一节所介绍例子的性能监视横切逻辑,并通过动态代理技术对此进行改造。在调用每一个目标类方法时启动方法的性能监视,在目标类方法调用完成时记录方法的花费时间。 

代码清单6-2  ForumService:包含性能监视横切代码 

Java代码   
  1. package com.baobaotao.proxy;  
  2. public class ForumServiceImpl implements ForumService {  
  3.     public void removeTopic(int topicId) {  
  4.               
  5.          //①-1开始对该方法进行性能监视  
  6.         PerformanceMonitor.begin(  
  7.                             "com.baobaotao.proxy.ForumServiceImpl. removeTopic");  
  8.         System.out.println("模拟删除Topic记录:"+topicId);  
  9.         try {  
  10.             Thread.currentThread().sleep(20);  
  11.         } catch (Exception e) {  
  12.             throw new RuntimeException(e);  
  13.         }         
  14.   
  15.          //①-2结束对该方法进行性能监视  
  16.         PerformanceMonitor.end();  
  17.     }  
  18.   
  19.     public void removeForum(int forumId) {  
  20.           //②-1开始对该方法进行性能监视  
  21.         PerformanceMonitor.begin(  
  22. "com.baobaotao.proxy.ForumServiceImpl. removeForum");  
  23.         System.out.println("模拟删除Forum记录:"+forumId);  
  24.         try {  
  25.             Thread.currentThread().sleep(40);  
  26.         } catch (Exception e) {  
  27.             throw new RuntimeException(e);  
  28.         }         
  29.   
  30.          //②-2结束对该方法进行性能监视  
  31.         PerformanceMonitor.end();  
  32.     }  
  33. }  


代码清单6-2中粗体表示的代码就是具有横切逻辑特征的代码,每个Service类和每个业务方法体的前后都执行相同的代码逻辑:方法调用前启动PerformanceMonitor,方法调用后通知PerformanceMonitor结束性能监视并给记录性能监视结果。 

PerformanceMonitor是性能监视的实现类,我们给出一个非常简单的实现版本,其代码如代码清单6-3所示: 

代码清单6-3  PerformanceMonitor 

Java代码   
  1. package com.baobaotao.proxy;  
  2. public class PerformanceMonitor {  
  3.      //①通过一个ThreadLocal保存调用线程相关的性能监视信息  
  4.     private static ThreadLocal<MethodPerformace> performanceRecord =          
  5.                                 new ThreadLocal<MethodPerformance>();  
  6.       
  7.     //②启动对某一目标方法的性能监视  
  8.      public static void begin(String method) {  
  9.         System.out.println("begin monitor...");  
  10.         MethodPerformance mp = new MethodPerformance(method);  
  11.         performanceRecord.set(mp);  
  12.     }  
  13.     public static void end() {  
  14.         System.out.println("end monitor...");  
  15.         MethodPerformance mp = performanceRecord.get();  
  16.   
  17.          //③打印出方法性能监视的结果信息。  
  18.         mp.printPerformance();  
  19.     }  
  20. }  


ThreadLocal是将非线程安全类改造为线程安全类的法宝,在9.2节中我们将详细介绍这个Java基础知识。PerformanceMonitor提供了两个方法:通过调用begin(String method)方法开始对某个目标类方法的监视,method为目标类方法的全限定名;而end()方法结束对目标类方法的监视,并给出性能监视的信息。这两个方法必须配套使用。 

用于记录性能监视信息的MethodPerformance类的代码如所示: 

代码清单6-4  MethodPerformance 

Java代码   
  1. package com.baobaotao.proxy;  
  2. public class MethodPerformance {  
  3.     private long begin;  
  4.     private long end;  
  5.     private String serviceMethod;  
  6.     public MethodPerformance(String serviceMethod){  
  7.        this.serviceMethod = serviceMethod;  
  8.   
  9.        //①记录目标类方法开始执行点的系统时间    
  10.        this.begin = System.currentTimeMillis();   
  11.    
  12.     }  
  13.     public void printPerformance(){  
  14.        
  15.         //②获取目标类方法执行完成后的系统时间,并进而计算出目标类方法执行时间  
  16.         end = System.currentTimeMillis();   
  17.         long elapse = end - begin;  
  18.    
  19.         //③报告目标类方法的执行时间  
  20.         System.out.println(serviceMethod+"花费"+elapse+"毫秒。");    
  21.     }  
  22. }  


通过下面的代码测试拥有性能监视能力的ForumServiceImpl业务方法: 

Java代码   
  1. package com.baobaotao.proxy;  
  2.   
  3. public class TestForumService {  
  4.     public static void main(String[] args) {  
  5.         ForumService forumService = new ForumServiceImpl();  
  6.         forumService .removeForum(10);  
  7.        forumService .removeTopic(1012);  
  8.     }  
  9. }  


我们得到以下输出信息: 

引用
begin monitor... ①removeForum(10)方法的性能监视报告 
模拟删除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:移除性能监视横切代码 

Java代码   
  1. package com.baobaotao.proxy;  
  2.   
  3. public class ForumServiceImpl implements ForumService {  
  4.   
  5.     public void removeTopic(int topicId) {  
  6.                                 ①  
  7.         System.out.println("模拟删除Topic记录:"+topicId);  
  8.         try {  
  9.             Thread.currentThread().sleep(20);  
  10.         } catch (Exception e) {  
  11.             throw new RuntimeException(e);  
  12.         }  
  13.                               ①  
  14.     }  
  15.     public void removeForum(int forumId) {  
  16.                           ②  
  17.         System.out.println("模拟删除Forum记录:"+forumId);  
  18.         try {  
  19.             Thread.currentThread().sleep(40);  
  20.         } catch (Exception e) {  
  21.             throw new RuntimeException(e);  
  22.         }  
  23.                           ②  
  24.     }  
  25. }  


在代码清单6-5中的①和②处,原来的性能监视代码被移除了,我们只保留了真正的业务逻辑。 

从业务类中移除的性能监视横切代码当然不能漂浮在空气中,它还得找到一个安身之所,InvocationHandler就是横切代码的安家乐园,我们将性能监视的代码安置在PerformanceHandler中,如代码清单6-6所示: 

Java代码   
  1. 代码清单6-6  PerformanceHandler  
  2. package com.baobaotao.proxy;  
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5.   
  6. public class PerformanceHandler implements InvocationHandler {//①实现InvocationHandler  
  7.     private Object target;  
  8.     public PerformanceHandler(Object target){ //②target为目标的业务类  
  9.         this.target = target;  
  10.     }  
  11.     public Object invoke(Object proxy, Method method, Object[] args) ③  
  12.             throws Throwable {  
  13.         PerformanceMonitor.begin(target.getClass().getName()+"."+ method. getName());③-1  
  14.         Object obj = method.invoke(target, args);// ③-2通过反射方法调用业务类的目标方法  
  15.         PerformanceMonitor.end();③-1  
  16.         return obj;  
  17.     }  
  18. }  



③处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:创建代理实例 

Java代码   
  1. package com.baobaotao.proxy;  
  2. import java.lang.reflect.Proxy;  
  3. public class TestForumService {  
  4.     public static void main(String[] args) {  
  5.                  
  6.                //①希望被代理的目标业务类  
  7.         ForumService target = new ForumServiceImpl();   
  8.           
  9.                //②将目标业务类和横切代码编织到一起  
  10.         PerformanceHandler handler = new PerformanceHandler(target);  
  11.           
  12.                 //③根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例  
  13.         ForumService proxy = (ForumService) Proxy.newProxyInstance(    
  14.                 target.getClass().getClassLoader(),  
  15.                 target.getClass().getInterfaces(),  
  16.                 handler);  
  17.   
  18.                 //④调用代理实例  
  19.         proxy.removeForum(10);     
  20.         proxy.removeTopic(1012);  
  21.     }  
  22. }  


上面的代码完成业务类代码和横切代码的编织工作并生成了代理实例。在②处,我们让PerformanceHandler将性能监视横切逻辑编织到ForumService实例中,然后在③处,通过Proxy的newProxyInstance()静态方法为编织了业务类逻辑和性能监视逻辑的handler创建一个符合ForumService接口的代理实例。该方法的第一个入参为类加载器;第二个入参为创建代理实例所需要实现的一组接口;第三个参数是整合了业务逻辑和横切逻辑的编织器对象。

按照③处的设置方式,这个代理实例实现了目标业务类的所有接口,即Forum ServiceImpl的ForumService接口。这样,我们就可以按照调用ForumService接口实例相同的方式调用代理实例,如④所示。运行以上的代码,输出以下信息: 

引用
begin monitor... 
模拟删除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 

Java代码   
  1. package com.baobaotao.proxy;  
  2. import java.lang.reflect.Method;  
  3. import net.sf.cglib.proxy.Enhancer;  
  4. import net.sf.cglib.proxy.MethodInterceptor;  
  5. import net.sf.cglib.proxy.MethodProxy;  
  6.   
  7. public class CglibProxy implements MethodInterceptor {  
  8.     private Enhancer enhancer = new Enhancer();  
  9.     public Object getProxy(Class clazz) {  
  10.         enhancer.setSuperclass(clazz); //① 设置需要创建子类的类  
  11.         enhancer.setCallback(this);   
  12.         return enhancer.create(); //②通过字节码技术动态创建子类实例  
  13.    
  14.     }  
  15.   
  16.         //③拦截父类所有方法的调用  
  17.     public Object intercept(Object obj, Method method, Object[] args,   
  18.             MethodProxy proxy) throws Throwable {  
  19.         PerformanceMonitor.begin(obj.getClass().getName()+"."+method. getName());//③-1  
  20.         Object result=proxy.invokeSuper(obj, args); ③-2   
  21.         PerformanceMonitor.end();//③-1通过代理类调用父类中的方法  
  22.         return result;  
  23.     }  
  24. }  


在上面代码中,用户可以通过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创建的代理类 

Java代码   
  1. package com.baobaotao.proxy;  
  2. import java.lang.reflect.Proxy;  
  3. public class TestForumService {  
  4.     public static void main(String[] args) {  
  5.       CglibProxy proxy = new CglibProxy();  
  6.       ForumServiceImpl forumService = ①   
  7.                 (ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class);  
  8.       forumService.removeForum(10);  
  9.       forumService.removeTopic(1023);  
  10.     }  
  11. }  



在①中,我们通过CglibProxy为ForumServiceImpl动态创建了一个织入性能监视逻辑的代理对象,并调用代理类的业务方法。运行上面的代码,输入以下信息: 

引用
begin monitor... 
模拟删除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方法进行代理。 

分享到:
评论

相关推荐

    2024嵌入式大厂面经C++首创

    2024嵌入式大厂面经C++首创提取方式是百度网盘分享地址

    C++ 高性能爬虫代码,带UI

    C++ 高性能爬虫代码,带UI

    2024嵌入式面试资料裕日软件C笔试题

    2024嵌入式面试资料裕日软件C笔试题提取方式是百度网盘分享地址

    黑色素瘤分类数据集10015张7类别.7z

    数据集类型:图像分类用,不可用于目标检测无标注文件 数据集格式:仅仅包含jpg图片,每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数):10015 分类类别数:7 类别名称:[“0”,“1”,“2”,“3”,“4”,“5”,“6”] 更多信息:blog.csdn.net/FL1623863129/article/details/139561265

    2024年高尿酸及痛风疾病医药行业分析报告.pptx

    行业报告

    自由生活条件中老年人体力活动的分类研究

    体力活动对老年人的身心健康有很大影响。研究表明 65 岁以上的老年人缺少必要的体力锻炼,会增加跌倒的风险、会阻碍行动、会降低肌肉力量和丧失自主能力。积极的生活方式有助于老年人降低残疾和慢性病的风险,从而提高老年人的身心健康和幸福指数。世界卫生组织的一份报告表示,积极运动的老年人肌肉适应力强,器官功能正常,因此他们跌倒的风险比较低,并且拥有很高的认知能力。世界卫生组织建议老年人每周进行 30 分钟或 30 分钟以上的体力活动,每周 5 次不低于 10 分钟的适度体力活动或高水准的体力活动,来确保老年人的健康需求。因此,通过长期对日常活动等数据特征分析,可以更好的规划出,每天体力活动和久坐的时间比,从而提高老年人生活的质量。近年来,由于可穿戴设备在加工率、电池寿命、小型化和成本效益等方面的科技进 步,可穿戴监控设备得到快速发展。在过去的几年里,我们做了大量的工作,利用加速计、陀螺仪等惯性传感器设备,对老年人的体力活动进行监督测量。大多数现有的系统都是根据青少年指标获得数据集进行开发验证的,很少有系统将老年人纳入其数据采集范围。Rosario 等研究人员,用 PAC 系统对年轻人进行测试,并

    上市公司污染排放当量(2007-2022).xlsx

    详细介绍及样例数据:https://blog.csdn.net/T0620514/article/details/139567890

    基于Selenium的Java爬虫实战(内含谷歌浏览器Chrom和Chromedriver版本116.0.5841.0)

    资源包括: 1.Java爬虫实战代码 2.selenium学习笔记 3.代码演示视频 4.谷歌浏览器chrom116.0.5841.0 chrome-linux64.zip chrome-mac-arm64.zip chrome-mac-x64.zip chrome-win32.zip chrome-win64.zip 5.谷歌浏览器驱动器Chromedriver116.0.5841.0 chromedriver-linux64.zip chromedriver-mac-arm64.zip chromedriver-mac-x64.zip chromedriver-win32.zip chromedriver-win64.zip 特别说明:Chrome 为测试版(不会自动更新) 仅适用于自动测试。若要进行常规浏览,请使用可自动更新的标准版 Chrome。)

    2024嵌入式面试资料禾赛科技2021嵌入式开发

    2024嵌入式面试资料禾赛科技2021嵌入式开发提取方式是百度网盘分享地址

    基于Selenium的Java爬虫实战(内含谷歌浏览器Chrom和Chromedriver版本115.0.5790.90)

    资源包括: 1.Java爬虫实战代码 2.selenium学习笔记 3.代码演示视频 4.谷歌浏览器chrom115.0.5790.90 chrome-linux64.zip chrome-mac-arm64.zip chrome-mac-x64.zip chrome-win32.zip chrome-win64.zip 5.谷歌浏览器驱动器Chromedriver115.0.5790.90 chromedriver-linux64.zip chromedriver-mac-arm64.zip chromedriver-mac-x64.zip chromedriver-win32.zip chromedriver-win64.zip 特别说明:Chrome 为测试版(不会自动更新) 仅适用于自动测试。若要进行常规浏览,请使用可自动更新的标准版 Chrome。)

    华为OD机试C卷- 欢乐的周末(Java & JS & Python & C).md-私信看全套OD代码及解析

    私信博主免费看所有华为OD真题、考试报告、手撕代码、面试记录

    基于Selenium的Java爬虫实战(内含谷歌浏览器Chrom和Chromedriver版本115.0.5773.4)

    资源包括: 1.Java爬虫实战代码 2.selenium学习笔记 3.代码演示视频 4.谷歌浏览器chrom115.0.5773.4 chrome-linux64.zip chrome-mac-arm64.zip chrome-mac-x64.zip chrome-win32.zip chrome-win64.zip 5.谷歌浏览器驱动器Chromedriver115.0.5773.4 chromedriver-linux64.zip chromedriver-mac-arm64.zip chromedriver-mac-x64.zip chromedriver-win32.zip chromedriver-win64.zip 特别说明:Chrome 为测试版(不会自动更新) 仅适用于自动测试。若要进行常规浏览,请使用可自动更新的标准版 Chrome。)

    2023全球财富报告(英)-2023-76页.pdf

    2023全球财富报告(英)-2023-76页.pdf

    2024嵌入式面试资料指针经验总结

    2024嵌入式面试资料指针经验总结提取方式是百度网盘分享地址

    C++ MPI多进程并发

    C++ MPI多进程并发

    毕设:企业员工绩效考评系统的设计与实现-java语言的前后端分离的webapp

    本项目是java语言的前后端分离的webapp: ● 前端:html+mui+jquery,HBuilder开发,nginx部署 ● 后端:jdk8+springboot+mybatisPlus,idea开发,tomcat部署 ● 由于前后端分开开发,会产生跨域问题,故开发中用nginx做代理服务器 企业员工绩效考评系统是一个涉及人力资源管理、数据分析和技术实现的复杂项目。使用Java语言进行前后端分离的Web应用开发是一个不错的选择,因为它能够提供稳定、可扩展和易于维护的解决方案。以下是一个基于Java语言的企业员工绩效考评系统的设计与实现建议: 1. 需求分析 用户角色:确定系统的主要用户角色,如员工、部门经理、人力资源部门等。 核心功能: 员工自我评估:员工可以定期进行自我评估,提交工作表现和目标完成情况。 上级评估:部门经理可以对下属员工进行绩效评估,并提供反馈。 数据汇总与分析:人力资源部门可以汇总员工绩效数据,进行统计分析和报告生成。 实时通知与提醒:系统能够及时通知员工和管理者有关绩效评估的相关信息。 2. 技术选型 前端:HTML5、CSS3、JavaScript(可

    2024嵌入式面试资料2022交大捷普社招-C开发

    2024嵌入式面试资料2022交大捷普社招-C开发提取方式是百度网盘分享地址

    毕业设计-基于四元数变换的彩色图像水印算法设计与实现.zip

    毕业设计-基于四元数变换的彩色图像水印算法设计与实现. 题目:基于四元数变换的彩色图像水印算法设计与实现 ● 变换算法: QDFRNT, 四元数分数阶随机变换 、 QDFRFT, 四元数分数阶傅里叶变换 ● 水印算法: ● 基于 SVM 的自适应彩色图像水印算法 ● 基于量化的自适应彩色图像水印算法 ( TODO ### 一、引言 #### 1.1 研究背景 随着数字技术的飞速发展和广泛应用,图像已成为信息传播的重要形式之一。然而,由于图像易于复制和篡改,版权保护问题日益突出。水印作为一种有效的版权保护手段,通过在图像中嵌入不易察觉的标志或图案来标识图像的所有权,从而防止未经授权的复制和分发。传统的水印方法主要依赖于像素级别的操作,如改变图像的颜色或纹理,但这些方法容易被分析和去除。近年来,四元数变换作为一种非线性几何变换,被应用于图像处理领域,为水印算法的改进提供了新的思路。 #### 1.2 研究目的 本研究的目的是设计和实现一种基于四元数变换的彩色图像水印算法。通过在水印图像上施加四元数变换,使得水印对原图像的视觉质量影响最小,同时提高算法的鲁棒性,使其能够在多种图像处理操作(

    2024年小型通用减速机行业分析报告.pptx

    行业报告

    华为OD机试C卷- 迷宫问题(Java & JS & Python).md-私信看全套OD代码及解析

    私信博主免费看所有华为OD真题、考试报告、手撕代码、面试记录

Global site tag (gtag.js) - Google Analytics