Spring AOP 实现

来源:互联网 发布:有什么聊天软件 编辑:程序博客网 时间:2024/05/18 02:43

Spring AOP 实现

@(spring)[AOP]

spring aop的发展过程


  • Spring AOP 实现
    • 增强类型
      • 前置增强
        • schema方式实现
      • 环绕增强
      • 异常抛出增强
      • 引介增强
    • 创建切面
      • 静态方法匹配切面
    • 自动代理
    • 迎来新时代
      • 注解实现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 为目标类增加新的方法和属性

前置增强


  1. 定义增强类
  2. 使用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);}
  1. 定义引介增强
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);    }}
  1. 测试
    @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"/>

迎来新时代

注解实现AOP

SpringInAction.4th.面向切面的Spring