为了账号安全,请及时绑定邮箱和手机立即绑定

Spring基础使用(四)-------API方式使用AOP

标签:
Java 架构
1、pointCut定义
    <bean id="pointCutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedNames">
            <list>
                <value>act*</value>
            </list>
        </property>
    </bean>
2、before advice

自定义的before advice需要实现MethodBeforeAdvice接口:

public class TestBeforeAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] objects, Object o) throws Throwable
    {
        System.out.println("TestBeforeAdvice | method is " + method.getName() +
        "   object is "+o.getClass().getName());
    }
}
3、throws advice

自定义的throws advice需要实现ThrowsAdvice接口,并在接口中定义afterThrowing方法。

afterThrowing方法有4种重载方式。

public class TestThrowAdvice implements ThrowsAdvice
{
    public void afterThrowing(Exception e)
    {
        System.out.println("TestThrowAdvice| afterThrowing 1");
    }
    public void afterThrowing(RemoteException e)
    {
        System.out.println("TestThrowAdvice| afterThrowing 2");
    }

    public void afterThrowing(Method method, Object[] args, Object target, Exception ex)
    {
        System.out.println("TestThrowAdvice| afterThrowing 3"+
                "method is "+method.getName()+
                "target is "+target.getClass().getName() );
    }

    public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)
    {
        System.out.println("TestThrowAdvice| afterThrowing 4"+
                "method is "+method.getName()+
                "target is "+target.getClass().getName() );
    }
}
4、after returning advice

自定义的返回后通知需要实现AfterReturningAdvice接口,定义afterReturning方法。方法中可以访问返回值,但是不能进行修改。如果抛出异常,则会抛出拦截器链,替代返回值

public class TestAfterReturningAdvice implements AfterReturningAdvice {

    public void afterReturning(Object o, Method method,
                               Object[] objects, Object o1)
    {
        System.out.println("TestAfterReturningAdvice| method is "+
                method.getName());
    }
}
5、环绕通知Interception

自定义的环绕通知,需要实现MethodInterceptor接口,实现invoke方法。

public class TestMethodInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation methodInvocation) throws Throwable 
    {
        System.out.println("TestMethodInterceptor| invoke 1,"+
        methodInvocation.getMethod().getName()+","+
        methodInvocation.getStaticPart().getClass().getName());

        Object o =  methodInvocation.proceed();

        System.out.println("TestMethodInterceptor| invoke 2,"+
                methodInvocation.getMethod().getName()+","+
                methodInvocation.getStaticPart().getClass().getName());

        return o;
    }
}
6、ProxyFactoryBean

ProxyFactoryBean用于生成对应的代理类,配合上述通知,共同实现API方式的AOP功能。

注入:

    <bean id="pointCutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedNames">
            <list>
                <value>act*</value>
            </list>
        </property>
    </bean>
    <bean id="testBeforeAdvice" class="learn.advice.TestBeforeAdvice"/>
    <bean id="afterReturningAdvice" class="learn.advice.TestAfterReturningAdvice"/>
    <bean id="testThrowAdvice" class="learn.advice.TestThrowAdvice"/>
    <bean id="testMethodInterceptor" class="learn.advice.TestMethodInterceptor"/>

    <bean class="learn.service.ControllerImlp" id="controllerImlpTarget"/>

    <bean id="defaultPointcutAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice" ref="testBeforeAdvice"/>
        <property name="pointcut" ref="pointCutBean"/>
    </bean>

    <bean id="controllerImlp" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="learn.interfaces.IController"/>
        <property name="target" ref="controllerImlpTarget"/>
        <property name="interceptorNames">
            <list>
                <value>defaultPointcutAdvisor</value>
                <value>afterReturningAdvice</value>
                <value>testThrowAdvice</value>
                <value>testMethodInterceptor</value>
            </list>
        </property>
    </bean>

执行:

IController helloService = (IController) context.getBean("controllerImlp");
        helloService.action();

结果

TestBeforeAdvice | method is action   object is learn.service.ControllerImlp
TestMethodInterceptor| invoke 1,action,java.lang.reflect.Method
action!!!!!
TestMethodInterceptor| invoke 2,action,java.lang.reflect.Method
TestAfterReturningAdvice| method is action

说明:

  • 程序代码中,可以看到只有before advice是通过切入点进行匹配的,其他通知未进行接入点匹配。从运行结果可以看到,默认是能够执行所有对应通知的。pointCut的意义在于进行更精确的匹配。

  • 在ProxyFactoryBean中如果指定了proxyInterfaces,则一定会走JDK的代理。如果对应的对象没有接口,则会使用CGLIB代理。

  • 可以使用内部匿名bean来隐藏目标和代理之间的差别。
    <bean id="controllerImlp" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces" value="learn.interfaces.IController"/>
        <!--这里直接定义bean,不再使用ref-->
        <property name="target">
            <bean class="learn.service.ControllerImlp"/>
        </property>
        <property name="interceptorNames">
            <list>
                <value>defaultPointcutAdvisor</value>
                <value>afterReturningAdvice</value>
                <value>testThrowAdvice</value>
                <value>testMethodInterceptor</value>
            </list>
        </property>
    </bean>
  • 如果在interceptorNames属性中使用通配符"*"匹配通知,则只能匹配Interceptor,其他通知无法匹配

  • 使用父子bean简化xml定义
    <!--定义父bean-->
    <bean id="baseProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"
        abstract="true"/>
    <!--使用父bean-->
    <bean id="controllerImlp" parent="baseProxyFactoryBean">
        <property name="proxyInterfaces" value="learn.interfaces.IController"/>
        <property name="target" ref="controllerImlpTarget"/>
        <property name="interceptorNames">
            <list>
                <value>defaultPointcutAdvisor</value>
                <value>afterReturningAdvice</value>
                <value>testThrowAdvice</value>
                <value>testMethodInterceptor</value>
            </list>
        </property>
    </bean>
  • 使用Spring AOP可以不依赖于IoC,也可以通过硬编码实现,只是不推荐。
7、auto-proxy

使用BeanNameAutoProxyCreator

    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="con*"/>
        <property name="interceptorNames">
            <list>
                <value>testBeforeAdvice</value>
            </list>
        </property>
    </bean>
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
1万
获赞与收藏
1426

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消