Spring中动态代理设计模式

目录

一、什么是动态代理

二、动态代理开发步骤

2.1 搭建开发环境

2.2 具体过程

三、动态字节码技术

四、动态代理开发简化代理开发


一、什么是动态代理

其实不管是静态代理还是动态代理其本质都是一样的,都是通过代理类为目标类增加额外功能,从而方便目标类的维护,只是在实现的过程中有所区别

二、动态代理开发步骤

2.1 搭建开发环境

在动态代理开发的过程中,是需要一些依赖的,将这些依赖文件导入pom.xml文件中

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.1.14.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.8</version>
</dependency>
<dependency><groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.3</version>
</dependency>

2.2 具体过程

1)创建目标对象

在静态代理设计模式中,我们采取的是new对象的方式,这种方式是会产生耦合的,所以在动态代理的过程中使用Spring配置文件来创建对象

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>

2)添加额外功能

创建好目标类之后我们需要去添加额外功能,这里添加额外功能就不再是自己定义一个类了,而是去实现Spring中的MethodBeforeAdvice接口。实现了这个接口就可以达成在目标类之前添加额外功能。然后再配置文件中创建出这个类的对象

public class Before implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        // 在则个方法中添加额外功能
        System.out.println("----method before advice log----");
    }
}
<bean id="before" class="com.gl.demo.proxy.Before"/>

3)定义切入点

为什么要定义切入点呢?其实在类中会有许多方法,但是有的方法是不需要添加额外功能的,那么定义这个切入点就可以选择为哪些方法添加额外功能。引入一个新的aop:config标签然后再这个标签中定义切入点,这里的切入点表达式execution就决定了为哪些方法添加额外功能,这个表达式时为该类所有方法添加额外功能

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
</aop:config>

4)组装 

定义了切入点后肯定是要将额外功能添加进去的,所以这里就需要在配置文件中组装额外功能

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>
<bean id="before" class="com.gl.demo.proxy.Before"/>

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>

    <!-- 进行组装 -->
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

5)调用

通过前4步的过程所有的都已经准备好了,那最后一步获取到这个代理对象即可,但是我们发现这里根本就没有这个代理对象。那要怎么获取呢?

我们只需通过getBean标签获取到之前的目标类(原始类)对象即可。好,到了这里可能有的同学就会说了,获取目标类对象那不是白干了,其实不然,Spring已经帮我们加工好了这个类对象了,我们通过getBean获取到的这个类对象就已经是一个代理类对象了 。同时需要注意的是这个对象需要用之前实现的接口来接收(和之前实现同一个接口是一个道理)

public void test2() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
    UserService userService = (UserService) ctx.getBean("userService");
    userService.register();
    userService.login();
}

在这里我们发现额外功能的添加就已经完成了

三、动态字节码技术

有的同学就会好奇,明明没有这个代理类怎么能获取到这个代理类的对象呢?其实在Spring框架运行的时候会通过动态字节码技术,在JVM中创建这个代理类,等程序结束后随着JVM会一起消失。那么问题来了,什么是动态字节码技术?

动态字节码技术:通过第三方的动态字节码框架,在JVM中创建对应类的字节码,进而创建对象,当虚拟机结束时,动态字节码随之消失(由于使用这个技术,就不需要定义类文件,所以就不会造成静态代理中类文件过多,影响项目管理的问题

四、动态代理开发简化代理开发

初看这个动态代理开发,可能会有同学认为这不是比静态代理还要麻烦吗?静态代理我都只需要写一个代理类,这里还要写额外功能、切入点、甚至还要重新组装。其实不然,这里再创建一个类并为这个类做动态代理

public interface OrderService {
    void showOrder();
}
public class OrderServiceImpl implements OrderService{
    @Override
    public void showOrder() {
        System.out.println("OrderService核心功能");
    }
}

有了这个类之后,我想为这个类添加额外功能是不是还是要像之前那么麻烦呢?这里如果是添加已有的额外功能是不需要这么复杂的,只需要在配置文件中创建这个对象即可

<bean id="userService" class="com.gl.demo.proxy.UserServiceImpl"/>
<bean id="before" class="com.gl.demo.proxy.Before"/>
<!-- 只需要创建这个类对象即可-->
<bean id="orderService" class="com.gl.demo.proxy.OrderServiceImpl"/>

<aop:config>
    <aop:pointcut id="pc" expression="execution(* *(..))"/>
    <aop:advisor advice-ref="before" pointcut-ref="pc"/>
</aop:config>

然后进行测试,我们看一下这个类中的方法是否添加了额外功能

public void test3() {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config2.xml");
    OrderService orderService = (OrderService) ctx.getBean("orderService");
    orderService.showOrder();
}

结果显示这个新的类中的方法也加上了相同的额外功能

那么到这里可能又会有问题了,这么一加不是所有类的所有方法都会添加上这个额外功能了?这个问题问的好!这里就可以通过切入点表达式execution来决定具体是哪个类的哪个方法添加额外功能了。。。欲知后事如何。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值