基于代理类的AOP实现
spring中的AOP代理默认就是使用JDK动态代理实现的。在spring中使用ProxyFactoryBean 是创建AOP代理的最基本的方式(需要导入aop 和aoplliance两个包)
Spring 的通知类型
spring的通知按照是在目标类方法连接点的位置可分为一下五种:
通知类型 | 说明 |
---|---|
(环绕通知) org.aopllance.intercept.MethodInterceptor | 在目标方法执行前后实施增强,可用于日志和事务管理等功能 |
(前置通知)org.springframework.aop.MethodBeforeAdvice | 在目标方法执行前实施增强,可用于权限管理等功能 |
(后置通知) org.springframework.aop.AfterReturningAdvice | 在目标方法执行后实施增强,可用于关闭流、上传文件、删除文件等功能 |
(异常通知)org.springframework.aop.ThrowsAdvice | 在方法抛出异常后实施增强,可用于处理异常记录日志等 |
(引介通知) org.springframework.aop.IntroductionInterceptor | 在目标类中添加一些新的方法和属性,用于修改老版本的程序 |
ProxyFactoryBean
ProxyFactoryBean 是FactoryBean 接口的实现类 。FactoryBean 负责实例化一个Bean,ProxyfactoryBean 负责为其他Bean 创建代理实例。
ProxyFactoryBean常用的属性 :
属性名称 | 描述 |
---|---|
target | 代理的目标对象 |
proxyInterfaces (汉语:代理接口) | 代理实现的接口。多个接口可用以下形式: |
proxyTargetClass | 是否使用CGLIB代理,为true时,使用CGLIB代理 |
interceptorNames (汉语:拦截器) | 需要织入目标的Advice (即创建的切面类) |
singleton | 返回代理是否是单例,默认为true(返回单例实例) |
optimize | 当设置为true时,强制使用CGLIB代理 |
案例以环绕通知为例:
创建一个切面类 :
package com.itheima.proxyfactorybean;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//切面类
public class MyAspect implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
check_Permission();
//执行目标方法
Object obj = methodInvocation.proceed();
log();
return obj;
}
private void log() {
System.out.println("模拟记录日志。。。。");
}
private void check_Permission() {
System.out.println("模拟检查权限。。。。");
}
}
切面类继承了org.aopllance.intercept.MethodInterceptor(环绕通知)接口,并实现接口中的invoke()方法。
创建配置文件 applicationContext.xml: (ProxyFactoryBean的重要内容是配置文件的配置)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 目标类 -->
<bean id = "userDao" class = "com.itheima.proxyfactorybean.UserDaoImpl"></bean>
<!-- 切面类 -->
<bean id = "myAspect" class = "com.itheima.proxyfactorybean.MyAspect"></bean>
<!-- 使用Spring代理工厂定义一个名称为UserDaoProxy的代理对象 -->
<bean id = "userDaoProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定代理实现的接口 -->
<property name="proxyInterfaces" value = "com.itheima.proxyfactorybean.UserDao"></property>
<!-- 指定目标对象 -->
<property name="target" ref = "userDao"></property>
<!-- 指定切面 植入环绕通知 -->
<property name="interceptorNames" value = "myAspect"></property>
<!-- 指定代理模式 ture 使用cglib false(默认) jdk 动态代理 -->
<property name="proxyTargetClass" value = "true"></property>
</bean>
</beans>
在定义代理对象时,通过子元素指定了代理实现的接口、代理的目标对象、需要织入的目标类的通知(即切面类)、代理方式
创建测试类ProxyFatoryBeanTest:
package com.itheima.proxyfactorybean;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
public class ProxyFactoryBeanTest {
@Test
public void MyTest(){
String xmlPath = "com/itheima/proxyfactorybean/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserDao userDao = (UserDao) applicationContext.getBean("userDaoProxy");
userDao.addUser();
userDao.deleteUser();
((AbstractApplicationContext)applicationContext).close();
}
}
在校学习生,不定时更新。还请各位看官谅解。
(参考书籍:JAVA EE 企业级应用开发教程(Spring+SpringMVC+MyBatis))