源码学习之AOP(二)-增强使用

 

 

在上一篇中,我们介绍了aop相关的基本概念,简单介绍了下Spring AOP中的advice,这一篇我们就来熟悉下这些advice的使用。

 

增强类型

       按照增强在目标类方法中的连接点位置,增强分为以下五类:

  1. 前置增强

BeforeAdvice是spring中提供的前置接口,但因为目前只支持方法级别的通知,所以真正使用的前置增强接口是MethodBeforeAdviceBeforeAdvice则是留给以后扩展.

  1. 后置增强

BeforeAdvice类似,目前使用的后置增强接口是AfterReturningAdvice,AfterAdvice留给以后扩展。

  1. 环绕增强

通过MethodInterceptor表示环绕增强,在目标方法执行前后实施增强。

  1. 异常抛出增强

通过ThrowsAdvice表示异常抛出增强,这是一个标签接口,类似Serializable,用于告诉其他对象这个会对抛出的一场进行处理.

  1. 引介增强

引介增强是一种特殊的增强,它可以通过给目标类实现一个新的接口来创建方法和属性。

 

增强使用

       我们继续用上篇中的村口喇叭的场景来帮助我们理解增强使用。

Trumpet:

public class Trumpet {
    /**
     * 广播
     */
    public void broadcast(){
        System.out.println("广播中。。。");
    }
}

 

前置增强

       在广播前,我们对喇叭进行一次检修:

BeforeAdvice:

public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("对喇叭进行检修。。。");
    }
}

 

      test:

public class TestBeforeAdvice {
    public static void main(String[] args) {
        Advice beforeAdvice = new BeforeAdvice();
        Trumpet target = new Trumpet();

        ProxyFactory factory = new ProxyFactory();

        factory.setTarget(target);
        factory.addAdvice(beforeAdvice);

        Trumpet proxy = (Trumpet) factory.getProxy();
        proxy.broadcast();

    }
}

 

       运行结果:

 

 

后置增强

       在广播后,我们对喇叭进行一次保养

AfterAdvice:

 
public class AfterAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("对喇叭进行保养。。。");
    }
}

 

       test

public class TestAfterAdvice {
    public static void main(String[] args) {
        Advice afterAdvice = new AfterAdvice();
        Trumpet target = new Trumpet();

        ProxyFactory factory = new ProxyFactory();

        factory.setTarget(target);
        factory.addAdvice(afterAdvice);

        Trumpet proxy = (Trumpet) factory.getProxy();
        proxy.broadcast();

    }
}

 

      运行结果:

 

环绕增强

       在广播前,例行检查,在广播结束后,也进行保养

AroundAdvice:

public class AroundAdvice implements MethodInterceptor {

    private void before() {
        System.out.println("对喇叭进行检修。。。");
    }

    private void after() {
        System.out.println("对喇叭进行保养。。。");
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        before();
        Object result = methodInvocation.proceed();
        after();
        return result;
    }
}

 

test:

public class TestAroundAdvice {
    public static void main(String[] args) {
        Trumpet target = new Trumpet();
        Advice aroundAdvice = new AroundAdvice();

        ProxyFactory factory = new ProxyFactory();

        factory.setTarget(target);
        factory.addAdvice(aroundAdvice);

        Trumpet proxy = (Trumpet)factory.getProxy();
        proxy.broadcast();
    }
}

      

       运行结果:

 

      

异常抛出增强

       喇叭坏了(发生异常),通知广播取消

Trumpet修改,模拟异常情况:

/**
 * 模拟异常情况
 */
public void broken(){
    throw new RuntimeException();
}

 

ThrowsAdvice:

public class ThrowsAdvice implements org.springframework.aop.ThrowsAdvice {

    public void afterThrowing(Method method, Object[] args,Object target, Exception ex){
        System.out.println("喇叭坏了,今天休息。。。");
    }

}

 

test:

public class TestThrowsAdvice {
    public static void main(String[] args) {

        Trumpet target = new Trumpet();
        Advice throwsAdvice = new ThrowsAdvice();

        ProxyFactory factory = new ProxyFactory();

        factory.setTarget(target);
        factory.addAdvice(throwsAdvice);

        Trumpet proxy = (Trumpet)factory.getProxy();
        try{
            proxy.broken();
        }catch (Exception e){
            
        }

    }
}

 

 

运行结果:

 

*我们可以看到,我们的异常增强类实现了ThrowsAdvice接口,这个接口和

Serializable一样,没有提供抽象方法,就是一个标签接口,用来告诉其他对象他实现了什么功能,在我们这里,我们里面处理的方法名只能是afterthrowing(Method method,Object[] args,Object target, Excetion ex)

 

引介增强

       引介增强是一种特殊的增强,它不仅仅体现与在目标类的周围增加横切逻辑,更厉害的是,它可以给目标类实现本来没有实现的接口,从而达到扩展方法和属性的目的。

      还是继续用喇叭的例子,村里公共设施在配电室有个单独开关(扩展的接口),可以开启录音功能。

MonitorAccess:

public interface MonitorAccess {
    void setMonitorActive(Boolean b);
}

MonitorIntroduction:

public class MonitorIntroduction extends DelegatingIntroductionInterceptor implements MonitorAccess {

    private ThreadLocal<Boolean> monitor = new ThreadLocal<>();

    @Override
    public void setMonitorActive(Boolean b) {
        monitor.set(b);
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        if(monitor.get() != null &&  monitor.get()){
            System.out.println("对广播进行录音。。。");
        }
        return super.invoke(mi);
    }
}

 

xml:

<bean id="target" class="com.ljw.testSpringMode.aop.advice.Trumpet"></bean>

<bean id="introduction" class="com.ljw.testSpringMode.aop.advice.MonitorIntroduction"/>

<bean id="trumpet" class="org.springframework.aop.framework.ProxyFactoryBean"
    p:proxyInterfaces="com.ljw.testSpringMode.aop.advice.MonitorAccess"
    p:interceptorNames="introduction"
    p:target-ref="target"
    p:proxyTargetClass="true"
/>

 

 

test:

public class TestIntroduction {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:Trumpet.xml");
        Trumpet trumpet = (Trumpet) context.getBean("trumpet");
        trumpet.broadcast();

        MonitorAccess monitorAccess = (MonitorAccess) trumpet;
        monitorAccess.setMonitorActive(true);
        trumpet.broadcast();
    }
}

 

运行结果:

首先不开启开关:

 

开启以后:

 

 

总结

       在上面我们通过接口的形式来实现增强,通过编程的方式实现了代理,主要使用到了ProxyFactory和ProxyFactoryBean,有关它们的解析会在后面的源码分析中进行。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值