Springboot源码 TargetSource解析

Springboot源码 TargetSource解析

概述

在Spring框架中,AOP的核心就是AOP代理,而AOP代理的核心就是代理对象,而代理对象有可能是动态生成的,也有可能是预先存在的,在Spring框架中,预先存在的代理对象称为静态代理对象,动态生成的代理对象则使用CGLIB和JDK动态代理技术来实现,这里我们主要介绍CGLIB动态代理实现的过程。

Spring中使用CGLIB来对目标对象进行代理,生成的动态代理对象通常继承自目标对象的类型,同时又动态增加了一些方法用于实现增强逻辑。

TargetSource是Spring框架中一个非常重要的概念,用于描述代理对象和目标对象之间的关系。Spring中使用的代理分为两类,JDK动态代理和CGLIB动态代理,TargetSource就是用来描述这两种代理对象和原对象之间的关系,从而为代理对象提供目标对象的详细信息。

TargetSource

在Spring中,TargetSource是一个接口,声明了两个方法:

public interface TargetSource {

    Class<?> getTargetClass();

    Object getTarget() throws Exception;

    void releaseTarget(Object target) throws Exception;
}

其中getTargetClass方法用于获取目标对象的Class类型,getTarget方法用于获取目标对象实例,releaseTarget方法则用于释放目标对象实例,在代理方法正常执行结束或意外异常结束时,都需要调用该方法释放目标对象,以便下次使用。

被代理对象的生成

下面我们通过一个Product类实现一个简易版的CGLIB动态代理示例,代码如下:

public class Product {
    private String name;

    public Product(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

在代理代码中,我们需要借助CGLIB库才能生成一个代理对象,因此需要在pom.xml文件中加入以下依赖:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

代理类的生成过程如下:

public class ProductProxyFactory {
    public static Product getProductProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Product.class);
        enhancer.setCallback(new ProductMethodInterceptor());
        return (Product) enhancer.create();
    }
}

在以上代码中,我们使用了Enhancer类对Product类进行了代理,同时为代理对象设置了回调,回调类为ProductMethodInterceptor。

方法拦截器

方法拦截器是代理对象和原对象之间桥梁,负责对代理对象的方法进行增强,CGLIB动态代理为每个代理类都提供了一个MethodInterceptor接口,用于实现方法拦截器的相关逻辑。以下是一个简单的示例:

public class ProductMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before " + method.getName() + " invoked");
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("after " + method.getName() + " invoked");
        return result;
    }

}

在以上代码中,我们对Product类的所有方法进行了拦截,并在拦截器中在方法前后加了一些日志输出,以便于观察代理对象和原对象之间的交互。

示例说明

示例1:获取目标对象类名

public class Main {

    public static void main(String[] args) {
        Product product = new Product("手机");
        TargetSource targetSource = new SingletonTargetSource(product);
        System.out.println(targetSource.getTargetClass().getName());
    }

}

在以上示例中,我们创建了一个Product类的实例,然后将其包装成一个TargetSource对象,使用SingletonTargetSource实现,最后获取TargetSource的类名。

示例2:获取目标对象实例

public class Main {

    public static void main(String[] args) {
        Product product = new Product("手机");
        TargetSource targetSource = new SingletonTargetSource(product);
        try {
            Object result = targetSource.getTarget();
            System.out.println(((Product) result).getName());
            targetSource.releaseTarget(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

在以上示例中,我们创建了一个Product类的实例,然后将其包装成一个TargetSource对象,使用SingletonTargetSource实现,最后获取TargetSource的实例对象,并调用Product类的getName方法输出结果,最后需要调用releaseTarget方法释放目标对象。

总结

TargetSource是Spring框架中描述动态代理与原对象之间关系的接口,它提供了获取目标对象类名和实例对象的方法,同时也提供了释放目标对象实例的方法,以便于下次使用。通过以上示例,我们可以了解到Spring如何使用CGLIB动态代理生成代理对象,同时也了解了TargetSource在代理对象和原对象之间的联系,为后续深入了解Spring的AOP技术打下基础。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springboot源码 TargetSource解析 - Python技术站

(0)
上一篇 2023年5月30日
下一篇 2023年5月30日

相关文章

  • MySQL数据库之Purge死锁问题解析

    MySQL数据库之Purge死锁问题解析 在大并发系统中,数据库死锁问题是很常见的。而MySQL数据库在处理死锁时,会使用Purge线程来扫描事务日志,可能会出现Purge自身也发生死锁的情况,称作Purge死锁问题。本攻略将详细讲解Purge死锁问题的产生原因、解决方法以及常见的示例。 产生原因 Purge死锁问题的产生原因,主要是由于Purge线程在扫描…

    Java 2023年5月20日
    00
  • 正则表达式中的反向预搜索(上)

    当我们使用正则表达式时,有时候我们需要匹配的内容在某些条件下才成立,这时候就可以使用反向预搜索(lookbehind)来实现。反向预搜索是指在匹配字符时,先查找指定的字符后面是否满足一定的条件,如果满足再继续匹配。 反向预搜索有两种形式:正向零宽度断言(positive lookbehind)和负向零宽度断言(negative lookbehind)。正向零…

    Java 2023年5月23日
    00
  • Java字符串替换函数replace()用法解析

    Java字符串替换函数replace()用法解析 在Java中,我们常常需要对字符串进行替换操作。其中,最常用的就是 replace() 函数。本文将为你详细讲解 replace() 函数的使用方法和注意事项。 replace() 函数基本用法 replace() 函数的基本用法是:将原字符串中的某个字符或字符串替换成新的字符或字符串。 public Str…

    Java 2023年5月26日
    00
  • SpringBoot2零基础到精通之映射与常用注解请求处理

    SpringBoot2零基础到精通之映射与常用注解请求处理 Spring Boot是一个非常流行的Java框架,它可以帮助开发人员快速构建基于Spring的应用程序。在本文中,我们将详细讲解如何使用Spring Boot进行请求处理,并介绍常用的注解和映射方式。 常用注解 @Controller @Controller注解用于标记一个类为控制器,用于处理HT…

    Java 2023年5月15日
    00
  • 详解Linux下Nginx+Tomcat整合的安装与配置

    关于“详解Linux下Nginx+Tomcat整合的安装与配置”的完整攻略,以下是具体步骤和示例说明: 环境准备 首先确保你已经安装了Java、Tomcat和Nginx,如果没有安装,请先进行安装。 Nginx配置 修改Nginx配置文件/etc/nginx/nginx.conf,增加如下配置: upstream my_tomcat { server 127…

    Java 2023年6月2日
    00
  • java创建excel示例(jxl使用方法)

    关于“java创建excel示例(jxl使用方法)”的攻略,可以分以下步骤进行讲解: 1. 准备工作 在使用jxl创建Excel文件之前,需要先下载并导入jxl的jar包,可以通过以下方式导入: 将下载的jxl.jar文件拷贝至项目的lib目录下,然后右键点击该文件,选择“Build Path” -> “Add to Build Path”即可将其添加…

    Java 2023年6月15日
    00
  • Java线程关闭的3种方法

    下面我会详细讲解Java线程关闭的3种方法。 1. 使用标志位关闭线程 原理 使用一个boolean类型的变量作为线程的标志位,当需要关闭线程时,将标志位设为false,在run方法中判断标志位,如果为false,则退出线程。 示例代码 public class StopThreadByFlag extends Thread { private volati…

    Java 2023年5月18日
    00
  • 详解使用Spring的BeanPostProcessor优雅的实现工厂模式

    下面我将详细讲解使用Spring的BeanPostProcessor实现工厂模式的方法。 什么是工厂模式 首先,工厂模式是一种创建型设计模式,主要思想是将对象的创建过程封装在一个工厂类中,从而使得代码更加具有可扩展性和可维护性。在实现过程中,我们可以使用多种方式来封装对象的创建过程,比如工厂方法模式和抽象工厂模式。 什么是BeanPostProcessor …

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部