代理模式

一、概述

  代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。

二、图形描述

三、代码实现

静态代理,由于比较简单,所有把代码都合到一起了: 

// 需要被代理的接口
public interface BussinessInterface {
void execute();
} // 基础实现类
public class Bussiness implements BussinessInterface { @Override
public void execute() {
System.out.println("柯贤铭在做生意~~~");
}
} // 在基础实现类的基础之上,封装一层方法
public class BussinessProxy implements BussinessInterface { private BussinessInterface bussinessImpl; public BussinessProxy(BussinessInterface bussinessImpl) {
this.bussinessImpl = bussinessImpl;
} @Override
public void execute() {
System.out.println("前拦截...");
bussinessImpl.execute();
System.out.println("后拦截...");
}
} // 测试类,真正使用的时候,我们采用增强之后的实现类
public class TestAgent { public static void main(String[] args) {
BussinessInterface bussinessInterface = new Bussiness();
BussinessInterface newBuss = new BussinessProxy(bussinessInterface);
newBuss.execute();
}
}

效果截图:

静态总结:

优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。

缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。

动态代理模式,由于代码量较少,我也融合到一起:

// 定义接口
public interface UserService {
void saveUser();
} // 定义接口实现类及方法
public class UserServiceImpl implements UserService {
@Override
public void saveUser() {
System.out.println("调用 saveUser() 方法");
}
} // 定义代理工具类
public class MyProxyUtil {
public static UserService getProxyByJDK(UserService service) {
// 参数:目标对象的类加载器,目标对象的接口,代理对象的执行处理器
UserService userService = (UserService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志-开始");
Object obj = method.invoke(service, args);
System.out.println("记录日志-结束");
return obj;
}
});
return userService;
}
} // 测试类
public class Test { public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxyUtil.getProxyByJDK(userService);
// 调用目标对象方法
userService.saveUser();
System.out.println("===================================");
// 调用代理对象方法
proxy.saveUser();
}
}

测试截图:

动态代理的总结

优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。

缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。

CGLib 动态代理

CGLib 动态代理相对于 JDK 动态代理局限性就小了很多,目标对象不需要实现接口,底层是通过继承目标对象产生代理子对象

代码,只是工具类方法多了一个:

public static UserService getProxyByCglib(UserService service) {
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置需要增强的类的对象
enhancer.setSuperclass(UserServiceImpl.class);
// 设置回调方法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
long begin = System.currentTimeMillis();
System.out.println("记录程序开始");
Object object = methodProxy.invokeSuper(o, args);
long end = System.currentTimeMillis();
System.out.println("记录程序结束");
return object;
}
});
UserService userService = (UserService) enhancer.create();
return userService;
}

测试代码:

public class TestCglib {
public static void main(String[] args) {
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxyUtil.getProxyByCglib(userService);
// 调用目标对象方法
userService.saveUser();
System.out.println("===================================");
// 调用代理对象方法
proxy.saveUser();
}
}

测试结果:

总结:

Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。 我们要使用cglib代理必须引入 cglib的jar包

三种代理模式进行总的分析概括:

代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。

而AOP,是通过动态代理实现的。

一、简单来说:

  JDK动态代理只能对实现了接口的类生成代理,而不能针对类

  CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

二、Spring在选择用JDK还是CGLiB的依据:

(1)当Bean实现接口时,Spring就会用JDK的动态代理

(2)当Bean没有实现接口时,Spring使用CGlib是实现

(3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

三、CGlib比JDK快?

  (1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

  (2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

静态代理,动态代理和CGLIB代理模式的更多相关文章

  1. 静态代理、动态代理和cglib代理

    转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...

  2. 设计模式---JDK动态代理和CGLIB代理

    Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...

  3. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  4. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  5. JDK动态代理和 CGLIB 代理

    JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...

  6. Java动态代理和CGLib代理

    本文参考 在上一篇"Netty + Spring + ZooKeeper搭建轻量级RPC框架"文章中涉及到了Java动态代理和CGLib代理,在这篇文章中对这两种代理方式做详解 下 ...

  7. Java三种代理模式:静态代理、动态代理和cglib代理

    一.代理模式介绍 代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能. 简言之,代理模式就是 ...

  8. 总结两种动态代理jdk代理和cglib代理

    动态代理 上篇文章讲了什么是代理模式,为什么用代理模式,从静态代理过渡到动态代理. 这里再简单总结一下 什么是代理模式,给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原 ...

  9. spring的AOP动态代理--JDK代理和CGLIB代理区分以及注意事项

    大家都知道AOP使用了代理模式,本文主要介绍两个代理模式怎么设置以及区别,对原文一些内容进行了引用后加入了自己的理解和更深入的阐述:   一.JDK代理和CGLIB代理的底层实现区别* JDK代理只能 ...

  10. JDK动态代理和CGLIB代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

随机推荐

  1. 解决错误【selenium.common.exceptions.SessionNotCreatedException】

    以前能用,突然不能用了,是浏览器版本可能升级了,与原来的weddriver驱动版本不符合 解决办法:1.更新浏览器驱动, 2.降低浏览器版本

  2. Python学习日志-01

    一.使用入门 (1)问答环节 人们为何使用Python: 软件质量高:Python更注重可读性.一致性和软件质量,这将其与脚本语言世界中的其他工具区别开来.因为代码的设计致力于可读性,因此比起传统脚本 ...

  3. Java并发编程-Unsafe实现原理与Unsafe应用解析

    前言 Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别.不安全操作的方法,如直接访问系统内存资源.自主管理内存资源等,这些方法在提升Java运行效率.增强Java语言底层资源 ...

  4. Windows安装C的编译环境

    对于java开发者来说安装C的编译环境不是非常熟悉,因此本文对C的安装环境进行介绍以及windows编译Redis和Zookeeper的过程.MinGW主要用于按照gcc.make等环境,cywin用 ...

  5. eclipse .project文件 .classpath文件的作用

    .classpath文件的作用 可以参考.classpath文件的作用 .project文件的作用 确保你自己的eclipse能创建Java项目,并且正确编译运行helloworld,给eclipse ...

  6. java 中的线程池

    1.实现下面的一个需求,控制一个执行函数只能被五个线程访问 package www.weiyuan.test; public class Test { public static void main( ...

  7. SpringBoot项目部署到tomcat

    SpringBoot部署到tomcat 一.修改maven.xml 1.添加<.packaging>war</.packaging>,打包为war包 <packaging ...

  8. RocketMQ入门到入土(二)事务消息&顺序消息

    接上一篇:RocketMQ入门到入土(一)新手也能看懂的原理和实战! 一.事务消息的由来 1.案例 引用官方的购物案例: 小明购买一个100元的东西,账户扣款100元的同时需要保证在下游的积分系统给小 ...

  9. css盒子模型的深入理解,在块级、行内元素的区别和特性

    css盒子模型用于处理元素的内容.内边距.边框和外边距的方式简称.元素框的最内部分是实际的内容,直接包围内容的是内边距.内边距呈现了元素的背景.内边距的边缘是边框.边框以外是外边距,外边距默认是透明的 ...

  10. 5.scrapy过滤器

    scrapy过滤器 1. 过滤器 当我们在爬取网页的时候可能会遇到一个调转连接会在不同页面出现,这个时候如果我们的爬虫程序不能识别出 该链接是已经爬取过的话,就会造成一种重复不必要的爬取.所以我们要对 ...