编程式实现Spring AOP 引入(Introduction)和切面(Advisor)

1、引入(Introduction)

我们在编程式实现Spring AOP中,我们所提到的前置增强(Before Advice)、后置增强(After Advice)、环绕增强(Around Advice)都是对方法的增强;那么在我们实际的项目研发过程中,我们是否可以对类进行增强呢,答案是肯定的。在AOP中,对方法的增强,我们称之为织入(Weaving),而对类的增强,我们称之为引入(Introduction)。如何实现引入,我们通过如下的例子来给大家阐述。
我们先定义一个Greeting接口和该接口的实现类GreetingImpl

Greeting

public interface Greeting {
    void sayHello(String name);
}

GreetingImpl

public class GreetingImpl implements Greeting {

    @Override
    public void sayHello(String name) {
        System.out.println("Hello:"+name);
    }
}

我们再定义一个接口,接口叫做Apology

Apology

public interface Apology {
    void saySorry(String name);
}

我们不想在GreetingImpl直接去实现Apology接口,但是我们想在程序运行的时候动态的实现它。因为假如在GreetingImpl实现了这个接口,我们就必须修改GreetingImpl这个类,关键是我们现在不想修改这个类。于是,我们就借助Spring的引入增强。
实现引入增强,首先我们要先定义一个引入增强类,定义如下。

GreetingIntroAdvice

public class GreetingIntroAdvice extends DelegatingIntroductionInterceptor implements Apology {

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable 
    {
            return super.invoke(mi);
    }

    @Override
    public void saySorry(String name) {
        System.out.println("Sorry "+name);
    }
}

该增强类拓展了DelegatingIntroductionInterceptor类并实现了Apology 接口。在类中首先覆盖了父类的invoke方法,然后实现了Apology 的方法。我们想用这个类去增强GreetingImpl类的功能,那么GreetingImpl这个类就不用实现Apology 接口,就可以在程序运行的时候调用Apology接口的方法了。

public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();

        GreetingImpl greetingImpl = new GreetingImpl();

        proxyFactory.setTarget(greetingImpl);

        proxyFactory.addAdvice(new GreetingIntroAdvice());

        Apology greeting = (Apology) proxyFactory.getProxy();

        greetingImpl.sayHello("Ron.Zheng");

        greeting.saySorry("Ron.Zheng");
}

在上面的代码中,我们先new了一个代理工厂,然后new了一个GreetingImpl的实例,将该实例作为代理工厂的目标对象,同时在代理工厂中添加GreetingIntroAdvice 增强,通过代理工厂获取代理之后强制转换成Apology接口,调用其方法即可实现增强。

Hello:Ron.Zheng
Sorry Ron.Zheng

2、切面

在我们前面编程式实现Spring AOP 这篇文章中所提供的例子中。我们对方法的增强所采用的无论是前置增强、后置增强还是环绕增强,我们都可以将他们理解成方法拦截器,但是这个拦截器非常的武断,如果它所拦截的类,它就会拦截这个类中的所有方法。但是在大量的真实项目中,似乎我们只需要拦截一些指定的方法就行了,没必要拦截所有的方法。如何才能够实现只拦截一些指定的方法呢?就是我们接下来将介绍的AOP的一个很重要的工具—Advisor(切面)。
我们可以通过切面,将增强类与拦截匹配条件组合在一起,然后将这个切面配置到ProxyFactory中,从而生成代理。这里所说的“拦截匹配条件”指定就是我们一直所说的Pointcut(切点)。Advisor(切面)封装了Advice(增强)与Pointcut(切点)。
我们来看一个例子。
在Greeting接口中,我们增加两个方法goodMonrning和goodNight,然后在进行方法拦截时,我们只拦截good开头的方法,而不拦截sayHello方法。

Greeting

public interface Greeting {
    void sayHello(String name);

    void goodMonrning(String name);

    void goodNight(String name);
}

GreetingImpl

public class GreetingImpl implements Greeting {

    @Override
    public void sayHello(String name) {
        System.out.println("Hello:"+name);
    }

    @Override
    public void goodMonrning(String name) {
        System.out.println("Good Monrning:"+name);
    }

    @Override
    public void goodNight(String name) {
        System.out.println("Good Night:"+name);
    }
}

要实现我们上面说的只拦截good开头的方法,而不拦截sayHello方法功能,这里我们借助RegexpMethodPointcutAdvisor这个基于正则表达式的切面类。

public static void main(String[] args) {
        // 获得并设置切面
        RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
        advisor.setAdvice(new GreetingAroundAdvice());
        advisor.setPattern("com.aop1.service.GreetingImpl.good.*");

        // 配置代理
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new GreetingImpl());
        proxyFactory.addAdvisor(advisor);

        // 获取代理
        Greeting greeting = (Greeting) proxyFactory.getProxy();
        greeting.sayHello("Ron.Zheng");
        greeting.goodMonrning("Ron.Zheng");
}

我们new一个RegexpMethodPointcutAdvisor实例,设置切面的通知为我们在编程式实现Spring AOP 所提供的环绕通知GreetingAroundAdvice;然后设置对应的正则表达式,使得当且仅当执行以good开头的方法时才对对应方法进行增强,执行对应的增强逻辑。

Hello:Ron.Zheng
调用方法之前
Good Monrning:Ron.Zheng
调用方法之后

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RonTech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值