学科分类
目录
SSM框架

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 运行结果

点击此处
隐藏目录