Spring AOP 实现
@(spring)[AOP]
spring aop的发展过程
增强类型
spring 的aop底层是通过jdk动态代理和cglib动态代理技术为bean织入横切逻辑的。spring通过使用增强类定义横切逻辑。
Spring 提供了五种增强类型:
- 前置增强 : org.springframework.aop.MethodBeforeAdvice 是Spring目前可用的前置增强
- 后置增强 : org.springframework.aop.AfterReturningAdvice 目标方法后执行
- 环绕增强 : org.aopalliance.intercept.MethodInterceptor 目标方法前后执行
- 异常抛出增强 : org.springframework.aop.AfterReturningAdvice 抛出异常后执行
- 引介增强 : org.springframework.aop.support.DelegatingIntroductionInterceptor 为目标类增加新的方法和属性
前置增强
- 定义增强类
- 使用spring 的 ProxyFactory 将增强类目标类放入工厂,然后工厂实现代理
前置增强类:
public class BeforeAop implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("this is before advice...");
}
}
ProxyFactory完成代理:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml","classpath:spring-mvc.xml"})
public class AopTest {
@Test
public void beforeAdvice(){
Waiter target = new NaviWaiter();
// 前置增强
BeforeAdvice beforeAdvice = new BeforeAop();
// spring代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// JDK代理
proxyFactory.setInterfaces(target.getClass().getInterfaces());
proxyFactory.setTarget(target);
proxyFactory.addAdvice(beforeAdvice);
// 增强,设为true强制使用cglib代理(要引cglib库)
// proxyFactory.setOptimize(true);
Waiter waiter = (Waiter) proxyFactory.getProxy();
waiter.greetTo("miss");
}
}
schema方式实现
spring的xml中配置bean
<bean class="com.lemontree.spring.aoptalk.BeforeAop" id="beforeAop"/>
<bean class="com.lemontree.spring.service.NaviWaiter" id="target"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.lemontree.spring.service.Waiter"
p:interceptorNames="beforeAop"
p:target-ref="target"/>
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring.xml","classpath:spring-mvc.xml"})
public class AopTest {
@Autowired
private Waiter waiter;
@Test
public void schema(){
waiter.greetTo("tt");
}
}
环绕增强
顾名思义
代码和和前置增强直接看代码
环绕增强
public class ArroundAop implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] o = invocation.getArguments();
String s = (String) o[0];
System.out.println("this is around..."+s);
Object result = invocation.proceed();
System.out.println("this is ....");
return result;
}
}
异常抛出增强
ThrowsAdvice 并没有定义方法,他只是一个标识接口,spring会通过反射机制进行判断,但是必须以下面的方法签名进行定义:
void afterThrowing(Method method,Object[] args,Object target,Throwable);
方法名必须为afterThrowing,前三个参数可以选,要么都要要么都不要,最后一个是Throwable或它的子类
具体实现:
public class ThrowAop implements ThrowsAdvice {
//定义增强逻辑
public void afterThrowing(Method method,Object[] args,Object target,Exception ex)throws Throwable{
System.out.println("方法名"+method.getName());
System.out.println("异常名称"+ex.getMessage());
System.out.println("回滚一波~~~~~");
}
}
引介增强
引介增强比较特殊,他不是在目标方法中织入增强,而是为目标类创建新的方法和属性,所以增强的链接点是类级别的(上面的 增强是方法级别的)。
具体实现:
1. 定义一个接口:
public interface MoniterService {
void wathchYou(boolean isWatch);
}
- 定义引介增强
public class IntroductionAop extends DelegatingIntroductionInterceptor implements MoniterService{
private ThreadLocal<Boolean> moniMap = new ThreadLocal<>();
@Override
public void wathchYou(boolean isWatch) {
moniMap.set(isWatch);
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
if (moniMap.get()!=null && moniMap.get()){
System.out.println("do it!");
}
return super.invoke(mi);
}
}
- 测试
@Test
public void introAop(){
Waiter target = new NaviWaiter();
// 引介增强
IntroductionInterceptor introductionAop = new IntroductionAop();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(target.getClass().getInterfaces());
proxyFactory.setTarget(target);
proxyFactory.addAdvice(introductionAop);
Waiter waiter = (Waiter) proxyFactory.getProxy();
waiter.greetTo("mss");
System.out.println("-----------------------");
MoniterService moniterService = (MoniterService) waiter;
moniterService.wathchYou(true);
waiter.greetTo("mss");
}
创建切面
增强类存在一个问题:增强被织入目标类的所有方法中。所以就需要Spring AOP去定位连接点。
所以创建切面的目的:找到连接点 ,为对应的方法织入横切逻辑
静态方法匹配切面
StaticMethodMatcherPointcutAdvisor 代表一个静态方法匹配切面,通过StaticMethodMatcherPointcut 定义切点
切面的创建:
1. 创建切面
2. 将增强类放入到切面中
3. 工厂生成代理类
具体实现:
切面:
public class StaticMethod extends StaticMethodMatcherPointcutAdvisor {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return "greetTo".equals(method.getName());
}
}
测试:
@Test
public void staticAdvisor() {
Waiter target = new NaviWaiter();
// 前置增强
BeforeAop beforeAop = new BeforeAop();
// 静态普通方法名称匹配
StaticMethod staticMethod = new StaticMethod();
staticMethod.setAdvice(beforeAop);
// 代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(target.getClass().getInterfaces());
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(staticMethod);
//生成代理类
Waiter waiter = (Waiter) proxyFactory.getProxy();
waiter.greetTo("可以");
System.out.println("----------------");
waiter.serveTo("不可以?");
}
自动代理
先看看前面的schame
<bean class="com.lemontree.spring.aoptalk.BeforeAop" id="beforeAop"/>
<bean class="com.lemontree.spring.service.NaviWaiter" id="target"/>
<bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean"
p:proxyInterfaces="com.lemontree.spring.service.Waiter"
p:interceptorNames="beforeAop"
p:target-ref="target"/>
可以看出,每次生成一个代理类都需要用ProxyFactoryBean配置一遍,十分麻烦。
所以spring提供了新的创建类:
- BeanNameAutoProxyCreator
- DefaultAdvisorAutoProxyCreator
还有很多中,这里只讲两个
有了Creator方法就可以嘿嘿嘿了
新的schame配置:
<bean class="com.lemontree.spring.aoptalk.BeforeAop" id="beforeAop"/>
<bean class="com.lemontree.spring.service.NaviWaiter" id="waiter"/>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
p:interceptorNames="beforeAop"
p:beanNames="*er"
p:optimize="true"/>