Spring 提供了自动代理机制,可以让容器自动生成代理,从而把开发人员从繁琐的配置中解脱出来 。 具体是使用 BeanPostProcessor 来实现这项功能。

这三种自动代理创建器 为:BeanNameAutoProxyCreator     ,  DefaultAdvisorAutoProxyCreator  ,    AbstractAdvisorAutoProxyCreator。

1BeanPostProcessor

BeanPostProcessor 代理创建器的实现类可以分为 3 类:

类型 实现类
基于 Bean 配置名规则 BeanNameAutoProxyCreator
基于 Advisor 匹配规则 DefaultAdvisorAutoProxyCreator
基于 Bean 中的 AspectJ 注解标签的匹配规则 AnnotationAwareAspectJAutoProxyCreator

BeanPostProcessor 类继承关系

所有的自动代理器类都实现了 BeanPostPorcessor ,在容器实例化 Bean 时, BeanPostProcessor 将对它进行加工处理,所以自动代理创建器能够对满足匹配规则的 bean 自动创建代理对象。

2 BeanNameAutoProxyCreator

假设有以下两个实体类(用户与充电宝)。

用户类:

public class User {

    public void rent(String userId) {
System.out.println("User:租赁【充电宝】");
} public void back(String userId){
System.out.println("User:归还【充电宝】"); }
}

充电宝:

public class Charger {

    public void rent(String userId) {
System.out.println("Charger:【充电宝】被租赁");
}
}

我们希望通过 BeanNameAutoProxyCreator 通过 Bean 的名称来自动创建代理,实现增强:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="user" class="net.deniro.spring4.aop.User"/>
<bean id="charger" class="net.deniro.spring4.aop.Charger"/> <!-- 前置增强-->
<bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/> <!-- 使用 BeanNameAutoProxyCreator-->
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
p:beanNames="*er"
p:interceptorNames="rentBeforeAdvice"
p:optimize="true"
></bean>
</beans>

BeanNameAutoProxyCreator的 beanNames 属性允许指定一组需要自动代理的 Bean 名称, 这里可以使用 * 通配符 。

因为我们需要代理的类名分别是 user 与 charger,都是以 er 结尾的,所以我们这里定义为 *er

也可以通过 beanNames 的 value 值来明确指定需要代理的 Bean 名称,多个以逗号分隔(更常用)。

<!-- 指定自动代理的 Bean 名称-->
<property name="beanNames" value="user,charger">
</property>

也可以通过 list 方式来指定 beanNames 的值:

<property name="beanNames">
<list>
<value>user</value>
<value>charger</value>
</list>
</property>

p:optimize 设置为 true,则表示使用 CGLib 动态代理技术。

通过这样的配置之后,容器在创建 user 和 charger Bean 的实例时,就会自动为它们创建代理对象,而这一操作对于使用者来说完全是透明的 。

单元测试:

User user = (User) context.getBean("user");
Charger charger = (Charger) context.getBean("charger"); String userId = "001";
user.rent(userId);
charger.rent(userId);

输出结果:

准备租赁的用户 ID:001
User:租赁【充电宝】
准备租赁的用户 ID:001
Charger:【充电宝】被租赁

3 DefaultAdvisorAutoProxyCreator

切面 Advisor 是切点和增强的复合体,而 DefaultAdvisorAutoProxyCreator 能够扫描 Advisor, 并将 Advisor 自动织入到匹配的目标 Bean 中。

<bean id="user" class="net.deniro.spring4.aop.User"/>
<bean id="charger" class="net.deniro.spring4.aop.Charger"/> <!-- 前置增强-->
<bean id="rentBeforeAdvice" class="net.deniro.spring4.aop.RentBeforeAdvice"/> <!-- 静态正则表达式方法名匹配-->
<bean id="regexpAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
p:advice-ref="rentBeforeAdvice">
<!-- 匹配模式-->
<property name="patterns">
<list>
<!-- 匹配字符串-->
<value>.*rent.*</value>
</list>
</property>
</bean> <!-- 使用 DefaultAdvisorAutoProxyCreator-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

首先我们配置了以静态正则表达式方法名匹配的切面,然后直接配置了 DefaultAdvisorAutoProxyCreator Bean。

测试代码与输出结果与上一小节的 BeanNameAutoProxyCreator 相同。

JDK 动态代理是通过接口来实现方法拦截,所以必须确保要拦截的目标在接口中有定义。

CGLib 动态代理是通过动态生成代理子类来实现方法拦截,所以必须确保要拦截的目标方法可以被子类所访问,也就是目标方法必须定义为非 final, 且非私有实例方法 。

Spring 中如何自动创建代理(spring中的三种自动代理创建器)的更多相关文章

  1. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件

    精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件 内容简介:本文介绍 Spring Boot 的配置文件和配置管理,以及介绍了三种读取配置文 ...

  2. spring mvc从前台往后台传递参数的三种方式

     jsp页面: 第一种:使用控制器方法形参的方式(常用) 第二种:使用模型传参的方式(如果前台往后台传递的参数非常多,如果还使用形参的方式传递,非常复杂.我们可以使用模型传参的方式,把多 个请求的参数 ...

  3. ARM微处理器中支持字节、半字、字三种数据类型,地址的低两位为0是啥意思?

    问题: ARM微处理器中支持字节.半字.字三种数据类型,其中,字需要4字节对齐(地址的低两位为0).半字需要2字节对齐(地址的最低位为0).我想问的是括号中的内容是什么意思呢?请牛人帮忙解释一下!谢谢 ...

  4. Spring Boot将Mybatis返回结果转为驼峰的三种实现方式

    本文不再更新,可能存在内容过时的情况,实时更新请访问原地址:Spring Boot将Mybatis返回结果转为驼峰的三种实现方式: 我们通常获取Mybatis返回的数据结果时想要将字段以驼峰的形式返回 ...

  5. spring mvc从后台往前台传参数的三种方式

    第一种:使用Model对象(常用) 第一步:使用model对象往前台传递数据 第二步:在jsp中接收从后台传递过来的参数 第二种:使用HttpServletRequest对象 第一步:使用HttpSe ...

  6. CentOS7创建本地YUM源的三种方法

    这篇文章主要介绍了CentOS7创建本地YUM源的三种方法,本文讲解了使用CentOS光盘作为本地yum源.如何为CentOS创建公共镜像.创建完全自定义的本地源等内容,需要的朋友可以参考下     ...

  7. Windows 10 应用创建模糊背景窗口的三种方法

    原文 Windows 10 应用创建模糊背景窗口的三种方法 现代的操作系统中创建一张图片的高斯模糊效果非常容易,不过如果要在窗口中获得模糊支持就需要操作系统的原生支持了.iOS/Mac 和 Windo ...

  8. 02 Spring框架 简单配置和三种bean的创建方式

    整理了一下之前学习Spring框架时候的一点笔记.如有错误欢迎指正,不喜勿喷. 上一节学习了如何搭建SpringIOC的环境,下一步我们就来讨论一下如何利用ioc来管理对象和维护对象关系. <? ...

  9. Spring创建对象的三种方式以及创建时间

    创建对象的三种方式: 1.采用默认的构造函数创建 2.采用静态工厂方法 1.写一个静态工厂方法类 public class HelloWorldFactory { public static Hell ...

随机推荐

  1. Tableau Sheet

    通过Tableau Sheet自带的超市数据给出几种图表. 在左侧数据Data栏有一列是Dimenslons是维度,下面Measures是测度,维度可以理解为你需要筛选的条件,比如根据年份看,根据地区 ...

  2. 阿里域名 ssl tomcat

    1.首先注册一个域名 2.添加一个信息模板(域名服务里边) 3.域名解析(默认解析127.0.0.1)  可以ping 域名试下看是否解析了(阿里有参考视频) 4.ssl 证书   免费版,网上有教程 ...

  3. 多线程(三) 同步synchronized

    五.同步 1.锁 多线程程序一般是为了完成一些相同的工作而存在的,因此有时间也会共享一些资源,例如对象.变量等等,此时如果不对各个线程进行资源协调,就会出现一些冲突,从而导致程序功能失效.例如下面的示 ...

  4. NFS原理

    1.什么是NFS? 全称 network file system 网络文件系统 通过网络存储和组织文件的一种方法或机制. 什么是文件系统? 2.为什么要用共享存储? 前端所有的应用服务器接收到用户上传 ...

  5. C++ 编码导致编译错误

    记录一个问题 平时经常用Notepad++写C++,然后g++编译 最近出现一个莫名其妙的问题 原来是编译时遇到了非法字符 用Notepad++一看,原来文件的编码出现的变化 不是UTF-8或者其他对 ...

  6. myeclipse 工具栏 Run按钮不见了,怎么调出来啊?

    window-->new window,打开新窗口,按钮出现了.关闭老窗口,再关闭新窗口.再次打开MyEclipse,妥妥的了.

  7. keep-alive实现返回保留筛选条件及筛选结果

    实现页面返回时,保留筛选条件和筛选结果 说明 . keep-alive 是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM 实现 结合router实现部分页面缓存 模板应用 ...

  8. ping —— 虚拟机

    1. 主机ping 虚拟机 ping 不通    设置——虚拟机—— 防护墙——入站规则——  文件和打印共享 (回显请求-ICMPv4-In) 2.主机连接不上虚拟机中的sqlsrver   设置— ...

  9. 暑假集训#2 div1 J 四点直角 J - Space Invader 四点共面+跨立实验

    题意:给你四个点,判断能否先依次通过A,B两点,然后再在某个地方只进行一次直角转弯再一次经过C,D两点: #include <iostream> #include <cstdio&g ...

  10. touch:创建文件及修改文件时间戳

    touch 命令不光可以用来创建文件(当指定操作文件不存在时,该命令会在当前位置建立一个空文件),此命令更重要的功能是修改文件的时间参数(但当文件存在时,会修改此文件的时间参数). Linux 系统中 ...