java动态代理(JDK和cglib)

简介: java动态代理(JDK和cglib)

JAVA的动态代理
代理模式
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。

首先看一下静态代理:
1、Count.java
package net.battier.dao;

/**

  • 定义一个账户接口
  • @author Administrator
    */
    public interface Count {
    // 查看账户方法
    public void queryCount();
    // 修改账户方法
    public void updateCount();
    }
    2、CountImpl.java
    package net.battier.dao.impl;
    import net.battier.dao.Count;
  • 委托类(包含业务逻辑)
    public class CountImpl implements Count {
    @Override
    public void queryCount() {

     System.out.println("查看账户方法...");  
    

    }
    public void updateCount() {

     System.out.println("修改账户方法...");  
    

    、CountProxy.java
    //代码效果参考:http://www.zidongmutanji.com/bxxx/146312.html

  • 这是一个代理类(增强CountImpl实现类)
    public class CountProxy implements Count {
    private CountImpl countImpl;
    /**

    • 覆盖默认构造器
    • @param countImpl
      /
      public CountProxy(CountImpl countImpl) {
      this.countImpl = countImpl;
      System.out.println("事务处理之前");
      // 调用委托类的方法;
      countImpl.queryCount();
      System.out.println("事务处理之后");
      countImpl.updateCount();
      3、TestCount.java
      package net.battier.test;
      import net.battier.dao.impl.CountImpl;
      import net.battier.dao.impl.CountProxy;
      测试Count类
      public class TestCount {
      public static void main(String[] args) {
      CountImpl countImpl = new CountImpl();
      CountProxy countProxy = new CountProxy(countImpl);
      countProxy.updateCount();
      countProxy.queryCount();
      观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。
      再来看一下动态代理:
      JDK动态代理中包含一个类和一个接口:
      InvocationHandler接口:
      public interface InvocationHandler {
      public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
      }
      参数说明:
      Object proxy:指被代理的对象。
      Method method:要调用的方法
      Object[] args:方法调用时所需要的参数
      可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。
      //代码效果参考:http://www.zidongmutanji.com/zsjx/416403.html

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例
Ps:类加载器
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器;
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的;
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类;
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。
动态代理
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。
动态代理示例:
1、BookFacade.java
public interface BookFacade {
public void addBook();
2、BookFacadeImpl.java
import net.battier.dao.BookFacade;
public class BookFacadeImpl implements BookFacade {
public void addBook() {
System.out.println("增加图书方法。。。");
、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

  • JDK动态代理代理类
  • @author student
    public class BookFacadeProxy implements InvocationHandler {
    private Object target;
    • 绑定委托对象并返回一个代理类
    • @param target
    • @return
      public Object bind(Object target) {
      this.target = target;
      //取得代理对象
      return Proxy.newProxyInstance(target.getClass().getClassLoader(),
           target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
      
    • 调用方法
      public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {  
      
      Object result=null;
      System.out.println("事物开始");
      //执行方法
      result=method.invoke(target, args);
      System.out.println("事物结束");
      return result;
      3、TestProxy.java
      import net.battier.dao.impl.BookFacadeImpl;
      import net.battier.proxy.BookFacadeProxy;
      public class TestProxy {
      BookFacadeProxy proxy = new BookFacadeProxy();
      BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
      bookProxy.addBook();

//代码效果参考:http://www.zidongmutanji.com/zsjx/364725.html
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
1、BookFacadeCglib.java
2、BookCadeImpl1.java

  • 这个是没有实现接口的实现类
    public class BookFacadeImpl1 {
     System.out.println("增加图书的普通方法...");  
    
    3、BookFacadeProxy.java
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
  • 使用cglib动态代理
    public class BookFacadeCglib implements MethodInterceptor {

    • 创建代理对象
      public Object getInstance(Object target) {
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(this.target.getClass());
      // 回调方法
      enhancer.setCallback(this);
      // 创建代理对象
      return enhancer.create();
      // 回调方法
      public Object intercept(Object obj, Method method, Object[] args,

       MethodProxy proxy) throws Throwable {  
      

      proxy.invokeSuper(obj, args);
      return null;
      4、TestCglib.java
      import net.battier.dao.impl.BookFacadeImpl1;
      import net.battier.proxy.BookFacadeCglib;
      public class TestCglib {

      BookFacadeCglib cglib=new BookFacadeCglib();
      BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
      bookCglib.addBook();

相关文章
|
3月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
275 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
4月前
|
安全 Java 微服务
Java 最新技术和框架实操:涵盖 JDK 21 新特性与 Spring Security 6.x 安全框架搭建
本文系统整理了Java最新技术与主流框架实操内容,涵盖Java 17+新特性(如模式匹配、文本块、记录类)、Spring Boot 3微服务开发、响应式编程(WebFlux)、容器化部署(Docker+K8s)、测试与CI/CD实践,附完整代码示例和学习资源推荐,助你构建现代Java全栈开发能力。
480 1
|
4月前
|
Oracle Java 关系型数据库
新手必看:Java 开发环境搭建之 JDK 与 Maven
本文分享了 Java 学习中 JDK 安装配置与 Maven 使用的入门知识,涵盖 JDK 下载安装、环境变量设置、Maven 安装配置及本地仓库与镜像设置,帮助新手快速搭建 Java 开发环境。
406 0
|
5月前
|
安全 Java API
Java最新技术(JDK 11+) 及以上 Java 最新技术之集合框架实操应用详解
本示例基于Java最新技术(JDK 11+),涵盖集合框架的核心功能,结合Java 8+特性(如Stream API、Lambda表达式)与并发编程最佳实践。内容包括:List操作(初始化、Lambda过滤、Stream处理)、Map操作(流式过滤、ConcurrentHashMap原子操作、并行流)、Set操作(TreeSet排序、CopyOnWriteArraySet并发安全)、Queue/Deque操作(优先队列、双端队列)以及高级聚合操作(集合转换、分组统计、平均值计算)。 [代码下载](https://pan.quark.cn/s/14fcf913bae6)
99 4
|
8月前
|
Java Spring
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: ● JDK动态代理只提供接口的代理,不支持类的代理Proxy.newProxyInstance(类加载器, 代理对象实现的所有接口, 代理执行器) ● CGLIB是通过继承的方式做的动态代理 , 如果某个类被标记为final,那么它是无法使用 CGLIB做动态代理的。Enhancer.create(父类的字节码对象, 代理执行器)
|
7月前
|
缓存 监控 Java
java动态代理
本文介绍了Java中的动态代理及其优势,通过增强原有方法或拦截调用实现无侵入式代码扩展,如添加日志、缓存等。文章先讲解了静态代理的基本概念和实现方式,随后引出动态代理解决静态代理在多方法、多类场景下的局限性。通过JDK提供的InvocationHandler接口和Proxy类,展示了如何动态生成代理对象。最后,文章还探讨了代理Hook技术,包括寻找Hook点、选择代理方式以及替换原始对象的具体步骤。
210 0
|
8月前
|
监控 Java API
JDK动态代理和CGLIB动态代理
Java动态代理允许在运行时创建代理对象,增强或拦截目标类方法的执行。主要通过两种方式实现:JDK动态代理和CGLIB动态代理。JDK动态代理基于接口,利用`java.lang.reflect.Proxy`类和`InvocationHandler`接口;CGLIB则通过字节码技术生成目标类的子类作为代理,适用于未实现接口的类。两者均用于在方法执行前后添加额外逻辑,如日志记录、权限控制等,广泛应用于AOP框架中。
278 2
|
9月前
|
Dubbo Java 应用服务中间件
Java的动态代理
Java动态代理是一种强大的机制,允许在运行时创建接口的代理实例,并拦截方法调用。其核心组件包括`java.lang.reflect.Proxy`和`java.lang.reflect.InvocationHandler`。通过自定义接口、实现接口、编写`InvocationHandler`处理器并生成代理对象,可以灵活地增强方法功能,如日志记录、事务管理等。典型应用场景包括AOP、RPC、延迟加载和Mock测试。与CGLIB相比,JDK动态代理基于接口,性能稍慢但无需第三方库,适用于需要无侵入式增强的场合。
173 2
|
4月前
|
存储 Ubuntu 安全
在Ubuntu 16.04上安装openjdk-6/7/8-jdk的步骤
在整个安装过程中,你可能需要管理员权限,因此你可能要使用 `sudo` 来获取必要的权限。记得做完每一个步骤后,都要检查输出,以确保没有发生错误,并且每项操作都成功完成。如果在安装过程中遇到问题,查看 `/var/log/` 下的日志文件对于问题的解决可能是有帮助的。
265 21