ProxyFactoryBean
ProxyFactoryBean是FactoryBean接口的实现类,FactoryBean负责实例化一个Bean,而ProxyFactoryBean负责为其他Bean创建代理实例。在Spring中,使用ProxyFactoryBean是创建AOP代理的基本方式。
ProxyFactoryBean类中的常用可配置属性如表1所示。
表1 ProxyFactoryBean的常用属性
属性名称 | 描述 |
---|---|
target | 代理的目标对象 |
proxyInterfaces | 代理要实现的接口,如果多个接口,可以使用以下格式赋值 <list> <value></value> .... </list> |
proxyTargetClass | 是否对类代理而不是接口,设置为true时,使用CGLIB代理 |
interceptorNames | 需要织入目标的Advice |
singleton | 返回的代理是否为单实例,默认为true(即返回单实例) |
optimize | 当设置为true时,强制使用CGLIB |
对ProxyFactoryBean类有了初步的了解后,接下来通过一个典型的环绕通知案例,来演示Spring使用ProxyFactoryBean创建AOP代理的过程,具体步骤如下。
(1)在核心JAR包的基础上,再向chapter03项目的lib目录中导入AOP的JAR包spring-aop-4.3.6.RELEASE.jar和aopalliance-1.0.jar,如图1所示。
图1 添加的JAR包
关于这两个JAR包的介绍如下:
● spring-aop-4.3.6.RELEASE.jar:是Spring为AOP提供的实现包,Spring的包中已经提供。
● aopalliance-1.0.jar:是AOP联盟提供的规范包,该JAR包可以通过地址http://mvnrepository.com/artifact/aopalliance/aopalliance/1.0
下载。
(2)在src目录下,创建一个com.itheima.factorybean包,在该包中创建切面类MyAspect。由于实现环绕通知需要实现org.aopalliance.intercept.MethodInterceptor 接口,所以MyAspect类需要实现该接口,并实现接口中的invoke()方法,来执行目标方法,如文件1所示。
文件1 MyAspect.java
1 package com.itheima.factorybean;
2 import org.aopalliance.intercept.MethodInterceptor;
3 import org.aopalliance.intercept.MethodInvocation;
4 // 切面类
5 public class MyAspect implements MethodInterceptor {
6 @Override
7 public Object invoke(MethodInvocation mi) throws Throwable {
8 check_Permissions();
9 // 执行目标方法
10 Object obj = mi.proceed();
11 log();
12 return obj;
13 }
14 public void check_Permissions(){
15 System.out.println("模拟检查权限...");
16 }
17 public void log(){
18 System.out.println("模拟记录日志...");
19 }
20 }
这里为了演示效果,在目标方法前后分别执行了检查权限和记录日志的方法,这两个方法也就是增强的方法,也就是通知。
(4)在com.itheima.factorybean包中,创建配置文件applicationContext.xml,并指定代理对象,如文件2所示。
文件2 applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
6 <!-- 1 目标类 -->
7 <bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
8 <!-- 2 切面类 -->
9 <bean id="myAspect" class="com.itheima.factorybean.MyAspect" />
10 <!-- 3 使用Spring代理工厂定义一个名称为userDaoProxy的代理对象 -->
11 <bean id="userDaoProxy"
12 class="org.springframework.aop.framework.ProxyFactoryBean">
13 <!-- 3.1 指定代理实现的接口-->
14 <property name="proxyInterfaces"
15 value="com.itheima.jdk.UserDao" />
16 <!-- 3.2 指定目标对象 -->
17 <property name="target" ref="userDao" />
18 <!-- 3.3 指定切面,织入环绕通知 -->
19 <property name="interceptorNames" value="myAspect" />
20 <!-- 3.4 指定代理方式,true:使用cglib,false(默认):使用jdk动态代理 -->
21 <property name="proxyTargetClass" value="true" />
22 </bean>
23 </beans>
在文件2中,首先通过<bean>元素定义了目标类和切面,然后使用ProxyFactoryBean类定义了代理对象。在定义的代理对象中,分别通过<property>子元素指定了代理实现的接口、代理的目标对象、需要织入目标类的通知以及代理方式。
(5)在com.itheima.factorybean包中,创建测试类ProxyFactoryBeanTest,在类中通过Spring容器获取代理对象的实例,并执行目标方法,如文件3所示。
文件3 ProxyFactoryBeanTest.java
1 package com.itheima.factorybean;
2 import org.springframework.context.ApplicationContext;
3 import
4 org.springframework.context.support.ClassPathXmlApplicationContext;
5 import com.itheima.jdk.UserDao;
6 // 测试类
7 public class ProxyFactoryBeanTest {
8 public static void main(String args[]) {
9 String xmlPath = "com/itheima/factorybean/applicationContext.xml";
10 ApplicationContext applicationContext =
11 new ClassPathXmlApplicationContext(xmlPath);
12 // 从spring容器获得内容
13 UserDao userDao =
14 (UserDao) applicationContext.getBean("userDaoProxy");
15 // 执行方法
16 userDao.addUser();
17 userDao.deleteUser();
18 }
19 }
执行程序后,控制台的输出结果如图2所示。
图2 运行结果