目录

一:GoF之代理模式

1. 对代理模式的理解

2. 静态代理

3. 动态代理

3.1 JDK动态代理

3.2 CGLIB动态代理


一:GoF之代理模式

1. 对代理模式的理解

生活场景1:牛村的牛二看上了隔壁村小花,牛二不好意思直接找小花,于是牛二找来了媒婆王妈妈;这里面就有一个非常典型的代理模式。牛二不能和小花直接对接,只能找一个中间人。其中王妈妈是代理类,牛儿是目标类。王妈妈代替牛二和小花先见个面。(现实生活中的婚介所)【在程序中,对象A和对象B无法直接交互时

生活场景2:你刚到北京,要租房子,可以自己找,也可以找链家帮你找;其中链家是代理类,你是目标类。你们两个都有共同的行为:找房子。不过链家除了满足你找房子,另外会收取一些费用的。(现实生活中的房产中介)【在程序中,功能需要增强时】

西游记场景:八戒和高小姐的故事,八戒要强抢民女高翠兰。悟空得知此事之后怎么做的?悟空幻化成高小姐的模样,代替高小姐与八戒会面。其中八戒是客户端程序,悟空是代理类,高小姐是目标类。那天夜里,在八戒眼里,眼前的就是高小姐,对于八戒来说,他是不知道眼前的高小姐是悟空幻化的,在他内心里这就是高小姐,所以悟空代替高小姐和八戒亲了嘴儿;这是非常典型的代理模式实现的保护机制。代理模式中有一个非常重要的特点:对于客户端程序来说,使用代理对象时就像在使用目标对象一样。【在程序中,目标需要被保护时】

业务场景:系统中有A、B、C三个模块,使用这些模块的前提是需要用户登录,也就是说在A模块中要编写判断登录的代码,B模块中也要编写,C模块中还要编写,这些判断登录的代码反复出现,显然代码没有得到复用,可以为A、B、C三个模块提供一个代理,在代理当中写一次登录判断即可!代理的逻辑是:请求来了之后,判断用户是否登录了,如果已经登录了,则执行对应的目标,如果没有登录则跳转到登录页面。【在程序中,目标不但受到保护,并且代码也得到了复用】

(1)代理模式是GoF23种设计模式之一,属于结构型设计模式。

(2)代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不应该看到的内容和服务或者添加客户需要的额外服务。 通过引入一个新的对象来实现对真实对象的操作或者将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象来间接访问一个对象,这就是代理模式的模式动机。

(3)代理模式中的角色:

①代理类(代理主题)

②目标类(真实主题)

③代理类和目标类的公共接口(抽象主题):客户端在使用代理类时就像在使用目标类,不被客户端所察觉,所以代理类和目标类要有共同的行为,也就是实现共同的接口。

(4)代理模式的类图:

(5)代理模式在代码实现上,包括两种形式:

①静态代理。

②动态代理(JDK动态代理和CGLIB动态代理)。

2. 静态代理

订单业务接口OrderService类

package com.bjpowernode.proxy.service;// 订单业务接口
public interface OrderService {// 生成订单void generate();// 修改订单信息void modify();// 查看订单信息void detail();
}

接口的实现类OrderServiceImpl类

其中Thread.sleep()方法的调用是为了模拟操作耗时。

package com.bjpowernode.proxy.service.impl;import com.bjpowernode.proxy.service.OrderService;public class OrderServiceImpl implements OrderService {@Overridepublic void generate() {try {// 模拟订单生成耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已生成...");}@Overridepublic void modify() {try {// 模拟修改订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已修改...");}@Overridepublic void detail() {try {// 模拟查看订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("正在查看详情...");}
}

客户端进行访问测试

package com.bjpowernode.proxy.client;import com.bjpowernode.proxy.service.OrderService;
import com.bjpowernode.proxy.service.impl.OrderServiceImpl;public class Test {public static void main(String[] args) {OrderService orderService = new OrderServiceImpl();orderService.generate();orderService.modify();;orderService.detail();}
}

假如项目已上线,并且运行正常,只是客户反馈系统有一些地方运行较慢,要求项目组对系统进行优化;于是项目负责人就下达了这个需求。首先需要搞清楚是哪些业务方法耗时较长,于是让我们统计每个业务方法所耗费的时长?如果是你,你该怎么做呢?

第一种方案:直接修改Java源代码,在每个业务方法中添加统计逻辑,如下:

直接在原来的代码片段中进行修改!

package com.bjpowernode.proxy.service.impl;import com.bjpowernode.proxy.service.OrderService;public class OrderServiceImpl implements OrderService {@Overridepublic void generate() {// 执行前计时long begin = System.currentTimeMillis();try {// 模拟订单生成耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已生成...");// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}@Overridepublic void modify() {// 执行前计时long begin = System.currentTimeMillis();try {// 模拟修改订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已修改...");// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}@Overridepublic void detail() {// 执行前计时long begin = System.currentTimeMillis();try {// 模拟查看订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("正在查看详情...");// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}
}

缺点:需求可以满足,但显然是违背了OCP开闭原则,并且相同的代码写了很多遍;所以这种方案不可取!

第二种方案:再编写一个子类OrderServiceImplSub继承实现类OrderServiceImpl,在子类中重写每个方法,代码如下:

使用继承(泛化)关系以子类的方式存在,在子类方法中使用super关键子调用父类的方法耦合度比较高

package com.bjpowernode.proxy.service.impl;public class OrderServiceImplSub extends OrderServiceImpl{@Overridepublic void generate() {// 执行前计时long begin = System.currentTimeMillis();// 调用父类的方法super.generate();// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}@Overridepublic void modify() {// 执行前计时long begin = System.currentTimeMillis();// 调用父类的方法super.modify();// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}@Overridepublic void detail() {// 执行前计时long begin = System.currentTimeMillis();// 调用父类的方法super.detail();// 执行后计时long end = System.currentTimeMillis();System.out.println("耗费时长"+(end - begin)+"毫秒");}
}

这种方式也可以解决,但是存在两个问题:

缺点:虽然解决了OCP开闭原则,但是采用了继承的方式,导致代码之间的耦合度较高。

缺点:代码也没有得到复用。

第三种方案:使用代理模式(静态代理)

使用关联关系以属性的方式存在,代理对象和目标对象实现同一个接口,并把目标对象通过有参构造传过来,耦合度比继承低

代理对象

前面最初编写的OrderService接口就是公共接口、OrderServiceImpl就是目标对象,现在就需要编写一个代理对象;代理对象和目标对象要具有相同的行为,就要实现同一个或同一些接口!

package com.bjpowernode.proxy.service.impl;import com.bjpowernode.proxy.service.OrderService;// 代理对象(代理对象和目标对象要具有相同的行为,就要实现同一个或同一些接口)
// 客户端在使用代理对象的时候就像在使用目标对象一样。
public class OrderServiceProxy implements OrderService {// 将目标对象作为代理对象的一个属性,这种关系叫做关联关系,比前面的继承关系的耦合度低。// 注意:这里要写一个公共接口类型,因为公共接口耦合度低。private OrderService target;// 提供构造方法进行赋值public OrderServiceProxy(OrderService target) {this.target = target;}@Overridepublic void generate() { // 代理方法// 增强long begin = System.currentTimeMillis();// 调用目标对象的目标方法target.generate();long end = System.currentTimeMillis();System.out.println("耗时"+(end - begin)+"毫秒");}@Overridepublic void modify() {// 代理方法// 增强long begin = System.currentTimeMillis();// 调用目标对象的目标方法target.modify();long end = System.currentTimeMillis();System.out.println("耗时"+(end - begin)+"毫秒");}@Overridepublic void detail() {// 代理方法// 增强long begin = System.currentTimeMillis();// 调用目标对象的目标方法target.detail();long end = System.currentTimeMillis();System.out.println("耗时"+(end - begin)+"毫秒");}
}

编写测试

先创建一个目标对象,然后把目标对象作为属性传到代理对象当中,因为我们在代理对象当中的构造方法中使用的是它们共有的接口OrderService作为属性参数;所以就可以通过代理对象的代理方法完成操作!

package com.bjpowernode.proxy.client;import com.bjpowernode.proxy.service.OrderService;
import com.bjpowernode.proxy.service.impl.OrderServiceImpl;
import com.bjpowernode.proxy.service.impl.OrderServiceProxy;public class Test {public static void main(String[] args) {      // 创建目标对象OrderService target = new OrderServiceImpl();// 创建代理对象OrderService proxy = new OrderServiceProxy(target);// 调用代理对象的代理方法proxy.generate();proxy.modify();proxy.detail();}
}

优点:解决了OCP问题,采用代理模式的关联关系可以降低耦合度!

缺点:类爆炸,假设系统中有1000个接口,那么每个接口都需要对应代理类,这样类会急剧膨胀;仍然未解决代码复用问题,不好维护。
怎么解决类爆炸问题?
可以使用动态代理来解决这个问题;动态代理还是代理模式,只不过添加了字节码生成技术,可以在内存中为我们动态的生成一个class字节码,这个字节码就是代理类。

3. 动态代理

(1)在程序运行阶段,在内存中动态生成代理类,被称为动态代理,目的是为了减少代理类的数量和解决代码复用的问题!

(2)在内存当中动态生成类的技术常见的包括:

JDK动态代理技术:只能代理接口

CGLIB动态代理技术:CGLIB(Code Generation Library)是一个开源项目。是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。它既可以代理接口,又可以代理类底层是通过继承的方式实现的。性能比JDK动态代理要好(底层有一个小而快的字节码处理框架ASM)

Javassist动态代理技术:Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。(前面MyBatis已经讲过

OrderService接口

package com.bjpowernode.dynamic.proxy;// 订单业务接口
public interface OrderService {// 生成订单void generate();// 修改订单信息void modify();// 查看订单信息void detail();
}

OrderServiceImpl实现类

package com.bjpowernode.dynamic.proxy;public class OrderServiceImpl implements OrderService {@Overridepublic void generate() {try {// 模拟订单生成耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已生成...");}@Overridepublic void modify() {try {// 模拟修改订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("订单已修改...");}@Overridepublic void detail() {try {// 模拟查看订单耗时Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("正在查看详情...");}
}

3.1 JDK动态代理

需求:业务增强,获取每个方法的执行时间

注:我们采用动态代理的方式,在内存中生成代理类!

客户端程序

第一步:还是创建目标对象。

第二步:创建代理对象,这个代理对象是动态生成的,此时需要Proxy类newProxyInstance()方法,这个方法有三个参数:
①第一个参数:ClassLoader loader-类加载器,这个类加载器有什么用呢?
在内存当中生成的字节码也是class文件,要执行也得先加载到内存当中;加载类就需要类加载器,所以这里需要指定类加载器;并且JDK要求,目标类的类加载器必须和代理类的类加载器使用同一个。

第二个参数:Class<?>[] interfaces-代理类要实现的接口,代理类和目标类要实现同一个接口或一些接口;在内存中生成代理类的时候,这个代理类是需要告诉它实现哪些接口的

第三个参数:InvocationHandler h-调用处理器;InvocationHandler 被翻译为:调用处理器,是一个接口;在调用处理器接口中编写的增强的业务代码。既然是接口,就要编写接口的实现类。

package com.bjpowernode.dynamic.client;import com.bjpowernode.dynamic.proxy.OrderService;
import com.bjpowernode.dynamic.proxy.OrderServiceImpl;import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {// 创建目标对象OrderService target = new OrderServiceImpl();// 创建代理对象Object obj = Proxy.newProxyInstance(target.getClass().getClassLoader(),                     target.getClass().getInterfaces(),"调用处理器");// 调用代理对象的代理方法// 返回的是一个Object,实现的是同一个OrderService接口,所以可以向下转型OrderService proxyObj = (OrderService)  obj;proxyObj.generate();proxyObj.modify();proxyObj.detail();}
}

第三步: 着重解决上面的第三个参数:调用处理器的参数,肯定要写一个实现类去实现InvocationHandler接口

(1)为什么强行要求你必须实现InvocationHandler接口?
因为一个类实现接口就必须实现接口中的方法;并且必须实现invoke()方法,因为JDK在底层调用invoke()方法的程序已经提前写好了!
注意:invoke()方法不是我们程序员负责调用的,是JDK负责调用的。
(2) invoke方法什么时候被调用呢?

当代理对象调用代理方法的时候,注册在InvocationHandler调用处理器当中的invoke()方法被调用。

(3)invoke方法是JDK负责调用的,所以JDK调用这个方法的时候会自动给我们传过来这三个参数,我们可以在invoke方法的大括号中直接使用。invoke方法的三个参数:
第一个参数:Object proxy 代理对象的引用这个参数使用较少
第二个参数:Method method 目标对象上的目标方法。(要执行的目标方法就是它
第三个参数:Object[] args 目标方法上的实参(利用反射机制调用方法时要传的参数)

注意:invoke方法执行过程中,先使用TimeInvocationHandler(target)参数把目标对象传过来,然后在处理器中使用method参数通过反射机制来调用目标对象的目标方法;所以我们就需要目标对象,所以我们就提供了目标对象的属性,提供了构造方法用来赋值,根据前面TimeInvocationHandler(target)参数把传过来的目标对象进行赋值!

完整客户端程序

注:是在创建处理器对象InvocationHandler时,把目标对象传进去!并且要求目标对象和代理对象使用同一个类加载器和同一个接口(目标对象和代理对象要实现同一个接口)

package com.bjpowernode.dynamic.client;import com.bjpowernode.dynamic.proxy.OrderService;
import com.bjpowernode.dynamic.proxy.OrderServiceImpl;import java.lang.reflect.Proxy;public class Client {public static void main(String[] args) {// 创建目标对象OrderService target = new OrderServiceImpl();// 创建代理对象Object obj = Proxy.newProxyInstance(target.getClass().getClassLoader(),         target.getClass().getInterfaces(),new TimeInvocationHandler(target));// 调用代理对象的代理方法// 返回的是一个Object,实现的是同一个OrderService接口,所以可以向下转型OrderService proxyObj = (OrderService)  obj;// 调用方法是invoke方法里面的增强代码会执行,但是目标对象的目标方法并不会执行,// 所以需要在new TimeInvocationHandler()中把target目标对象传过去proxyObj.generate();proxyObj.modify();proxyObj.detail();}
}

用来增强代码的处理器程序

注:在处理器中把目标对象target以属性的方式展现出来!并重写invoke方法,在里面编写增强的代码,并通过反射机制的形式调用目标对象的方法!

package com.bjpowernode.dynamic.client;import com.bjpowernode.dynamic.proxy.OrderService;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class TimeInvocationHandler implements InvocationHandler {// 目标对象private Object target;// 构造方法,给成员变量赋值public TimeInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 增强代码long begin = System.currentTimeMillis();// 调用目标对象的目标方法(通过反射机制)// 方法四要素:哪个对象target,哪个方法method,传什么参数args,返回什么值retValueObject retValue = method.invoke(target, args);long end = System.currentTimeMillis();System.out.println("耗时"+(end - begin)+"毫秒");return retValue;}
}

细节:对于上面的代码一定要注意返回值的问题

现在我们的方法都是void没有返回值,看起来通过反射机制调用方法返回retValue没什么用;但是我们一旦提供一个有返回值的参数,如果不去return retValue,在客户端就获取不到这个值,获取到的就会是一个null!

封装一个工具类

package com.bjpowernode.dynamic.util;import com.bjpowernode.dynamic.client.TimeInvocationHandler;
import java.lang.reflect.Proxy;public class ProxyUtil {// 封装一个工具方法,可以通过这个方法获取代理对象。public static Object newProxyInstance(Object target){// 底层是调用的还是JDK的动态代理。return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new TimeInvocationHandler(target));}}

使用封装后的工具类

3.2 CGLIB动态代理

CGLIB既可以代理接口,又可以代理类代理类底层采用继承的方式实现(虽然继承的方式耦合性高,但这部分代码在内存中生存的,不需要我们手写,所以无所谓)!所以被代理的目标类不能使用final关键字修饰!

第一步:引入CGLIB的依赖

 <!--引入CJLIB的依赖-->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

第二步:准备一个没有实现接口的类(可以代理类

package com.bjpowernode.proxy.service;public class UserService {// 目标方法public boolean login(String username, String password){System.out.println("系统正在验证身份...");if ("admin".equals(username) && "123".equals(password)) {return true;}return false;}// 目标方法public void logout(){System.out.println("系统正在退出...");}
}

第三步:客户端程序,使用CGLIB在内存中为UserService类生成代理类,并创建对象

①首先创建一个字节码增强器,创建Enhancer对象

②因为cglib底层使用的是继承的方式实现,所以需要告诉cglib要继承哪个类,调用增强器的setSuperclass()方法,参数是我们的要代理类的.class

③调用增强器的setCallback方法,设置回调接口参数是一个方法拦截器MethodInterceptor,这个拦截器需要我们自己编写一个类去实现MethodInterceptor接口。

调用增强器的create()方法,生成源码,编译class并加载到JVM,并创建代理对象

⑤最后一步,调用代理对象的代理方法。

package com.bjpowernode.proxy.client;import com.bjpowernode.proxy.service.TimerMethodInterceptor;
import com.bjpowernode.proxy.service.UserService;
import net.sf.cglib.proxy.Enhancer;public class Client {public static void main(String[] args) {// 第一步:创建字节码增强器Enhancer enhancer = new Enhancer();// 第二步:告诉cjlib要继承那个类enhancer.setSuperclass(UserService.class);// 第三步:设置回调接口,参数是方法拦截器enhancer.setCallback(new TimerMethodInterceptor());// 第四步:生成源码,编译class,加载到JVM,并创建代理对象UserService userServiceProxy = (UserService)enhancer.create();// 第五步:调用方法// 调用代理对象的代理方法。boolean success = userServiceProxy.login("admin", "123");System.out.println(success ? "登录成功" : "登录失败");userServiceProxy.logout();}
}

可以输出以下userServiceProxy(代理对象),记住格式,根据这个名字可以推测框架底层是否使用了CGLIB动态代理;其实底层是:

com.bjpowernode.proxy.service.UserService$$EnhancerByCGLIB$$4a68228b@2471cca7

这个类继承了userServiceProxy这个代理对象

第四步:着重解决第三步的回调函数,方法拦截器问题

和JDK动态代理原理差不多,在JDK动态dialing中需要提供的是InvocationHandler,而CGLIB动态代理提供的是:MethodInterceptor,所以也要编写一个方法实现这个接口,并重写MethodInterceptor接口中的intercept()方法,该方法有4个参数:

第一个参数:Object target 目标对象;

第二个参数:Method method 目标方法;

第三个参数:Object[] objects 目标方法调用时的实参;

第四个参数:Method methodproxy 代理方法;

package com.bjpowernode.proxy.service;import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class TimerMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {// 前增强long begin = System.currentTimeMillis();// 调用目标,通过代理对象的invokeSuper方法Object retValue = methodProxy.invokeSuper(target, objects);// 后增强long end = System.currentTimeMillis();System.out.println("耗时" + (end - begin) + "毫秒");// 一定要返回return retValue;}
}

注:如果代理的是类,调用的是代理方法的invokeSuper方法参数就是intercept方法里面的目标对象和目标方法的参数。如果代理的是接口,就需要创建接口的实现类对象传过来(和JDK动态代理的思路相同),参数就是接口的实现类和目标方法的参数

测试结果

这是因为cjlib底层的问题,JDK高于8的就会出现这个问题!怎么解决呢?设置两个参数!

①先点击Modify options

② 选择 Add VM options

③设置以下两个参数

--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/sun.net.util=ALL-UNNAMED

④正常执行

总结:

Jdk动态代理(只能代理接口)的拦截对象是通过反射的机制来调用被拦截实例方法的,反射的效率比较低。所以cglib动态代理(既能代理接口又能代理类)采用了FastClass的机制来实现对被拦截方法的调用。FastClass机制就是对一个类的方法建立索引,调用方法时根据方法的签名来计算索引,通过索引来直接调用相应的方法。

【Spring6】| GoF之代理模式(JDK动态代理和CGLIB动态代理)相关推荐

  1. 什么是代理模式?代理模式有什么用?通过一个小程序分析静态代理和动态代理。自己简单实现动态代理。JDK动态代理和CGLIB动态代理的区别。

    1. 代理模式有什么用 ①功能增强,在实现目标功能的基础上,又增加了额外功能.就像生活中的中介一样,他跟两边客户会有私下的交流. ②控制访问,代理不让用户直接和目标接触.就像中间商一样,他们不会让我们 ...

  2. Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理

    Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理 代理模式 JDK动态代理 CGLIB动态代理 代理模式 代理模式是23种设计模式的一种,指一个对象A通过持有另一个对象B,可以具有B ...

  3. jdk动态代理和cglib动态代理实现及区别

    代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 代理模式又分为:静态代理.jdk动态代 ...

  4. Java两种动态代理JDK动态代理和CGLIB动态代理

    目录 代理模式 JDK动态代理 cglib动态代理 测试 代理模式 代理模式是23种设计模式的一种,他是指一个对象A通过持有另一个对象B,可以具有B同样的行为的模式.为了对外开放协议,B往往实现了一个 ...

  5. Java中动态代理的两种方式JDK动态代理和cglib动态代理以及区别

    视频功能审核通过了,可以看视频啦!记得点关注啊~ 注意:因为网络原因,视频前一两分钟可能会比较模糊,过一会儿就好了 记得点关注啊,视频里的wx二维码失效了,wx搜索:"聊5毛钱的java&q ...

  6. 利用代码分别实现jdk动态代理和cglib动态代理_面试之动态代理

    大家好!我是CSRobot,从今天开始,我将会发布一些技术文章,内容就是结合春招以来的面试所遇到的问题进行分享,首先会对知识点进行一个探讨和整理,在最后会给出一些面试题并作出解答,希望可以帮助到大家! ...

  7. JDK动态代理和CGLib动态代理简单演示

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例. 一.首先我们进行JDK动态代理的演示. 现在我们有一个简单的业务接口Saying,如下: package te ...

  8. JAVA 进阶篇 动态代理 JDK动态代理和CGlib动态代理

    JDK动态代理和CGlib动态代理 JDK动态代理: 利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. CGlib动态代理: 利用ASM(开源的Java ...

  9. Spring AOP之---基于JDK动态代理和CGLib动态代理的AOP实现

    AOP(面向切面编程)是OOP的有益补充,它只适合那些具有横切逻辑的应用场合,如性能监测,访问控制,事物管理,日志记录等.至于怎么理解横切逻辑,敲完实例代码也就明白了. 为什么要使用AOP,举个栗子: ...

最新文章

  1. Struts2中的拦截器与过滤器学习
  2. Silverlight 3 Tools 中文版地址
  3. Python的函数名作为参数传入调用以及map、reduce、filter
  4. HBuilderX代码设置断点或者书签
  5. OpenGL:着色器shader
  6. 【IT笔试面试题整理】给定一个数组a[N]构造数组b [N]
  7. javaone_JavaOne 2014 –有关提交的一些初步分析
  8. cdatabase读取excel第一行数据_pandas读取excel数据并对重复数据进行标记或者删除
  9. 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式
  10. 基于顺序存储结构的图书信息表的旧图书的出库(C++)
  11. 在unity向量空间内绘制几何(4): 利用平面几何知识画像素直线
  12. VC调用Delphi对象接口
  13. 【LeetCode】【字符串】题号:*389. 找不同
  14. 国密算法使用-SM3
  15. 解决“安装程序无法创建新的系统分区,也无法定位现有系统分区”问题方法
  16. 怒了,以后有文件保存到网上
  17. php office 在线预览,在线预览pdf和Office文档
  18. unity如何实现图片透视_FPS透视自瞄从入门到入狱
  19. 手机浏览器播放mp3等音乐(chrome特殊)
  20. 湖南任务书 数据库服务渗透测试

热门文章

  1. python_learn 装饰器
  2. Linux 应用编程之strerror函数
  3. 百度地图实现只展示某一个省份地图,点击市以后高亮
  4. QQ邮件定时发送天气预报
  5. 以数据驱动管理转型,元年科技正当时
  6. 以下哪一个不属于python语言的特点-以下选项不属于 Python 语言特点的是
  7. android java 数组转字符串_java – Android将字符串转换为数组字符串
  8. 2-8时间窃取函数以及SQL注入应用
  9. ORM框架了解以及优缺点
  10. opencv提取图像中的颜色直方图(RGB、HSV)