SpringAOP之注入AspectJ切面

写在开头:
本文参考资料为Spring In Action(第4版),文中理解不对之处均为本人原因,与书籍无关。

Spring In Action中提到:“Spring AOP构建在动态代理之上,因此,Spring对AOP的支持局限于方法拦截”。

那么,当我们需要创建更细粒度的通知或想监测bean的创建时,Spring所支持的AOP就比较弱了,这时,可以选择使用AspectJ提供的构造器切点,并且可以借助Spring的依赖注入把bean装配进AspectJ切面中。下面就来举个栗子:

//定义表演接口
package concert;
public interface Performance {
    void perform(); 

    void finishPerform(String performer, String title); 
}
//定义钢琴表演
package concert;
public class PianoPerform implements Performance {
    public PianoPerform(){
        System.out.println("有请钢琴表演");
    }

    @Override
    public void perform() {
        System.out.println("钢琴表演开始");
    }

    @Override
    public void finishPerform(String performer, String title) {
        System.out.println(performer + "演奏钢琴曲:" + title);
    }
}
//定义小提琴表演
package concert;
public class ViolinPerform implements Performance {
    public ViolinPerform(){
        System.out.println("有请小提琴表演");
    }

    @Override
    public void perform() {
        System.out.println("小提琴表演开始");
    }

    @Override
    public void finishPerform(String performer, String title){
        System.out.println(performer + "演奏了小提琴曲:" + title);
    }   
}
//定义工作人员,将作为切面的协作bean
package concert;
public class Worker {
    public void take(){
        System.out.println("观众已全部交出手机");
    }

    public void sendMsg(String name){
        System.out.println(name + "表演即将开始,请各位观众交出手机");
    }

    public void broadcast(String performer, String title){
        System.out.println(performer + "演奏完毕,刚才演奏的曲子叫:" + title);
    }
}
//定义切面
package concert;
public aspect Audience {    
    private Worker worker;

    public Audience(){}

    //通过setter方法注入
    public void setWorker(Worker worker){
        this.worker = worker;
        System.out.println("工作人员已入场");
    }

    //定义piano构造器切点和后置通知
    pointcut piano():execution(concert.PianoPerform.new());
    after():piano(){
        worker.sendMsg("钢琴");
    }

    //定义violin构造器切点和后置通知
    pointcut violin():execution(concert.ViolinPerform.new());
    after():violin(){
        worker.sendMsg("小提琴");
    }

    //定义不带参数方法切点和前置通知
    pointcut perform():execution(* concert.Performance.perform());
    before():perform(){
        worker.take();
    }

    //定义带两个参数的切点和后置通知
    pointcut finishPerform(String performer, String title):execution(* concert.Performance.finishPerform(String, String)) && args(performer, title);
    after(String performer, String title):finishPerform(performer, title){
        worker.broadcast(performer, title);
    }
}

XML配置文件:spring.xml

"1.0" encoding="UTF-8"?>
"http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    

    "worker" class="concert.Worker"/>

    
    "concert.Audience" factory-method="aspectOf">
        "worker" ref="worker" />
    

    
    
    

    "piano" class="concert.PianoPerform"/>

    "violin" class="concert.ViolinPerform"/>
//主程序
package concert;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");

        Performance piano = context.getBean("piano", Performance.class);
        piano.perform();
        piano.finishPerform("亚莎·海菲兹", "致爱丽斯");

        Performance violin = context.getBean("violin", Performance.class);
        violin.perform();
        violin.finishPerform("霍洛维茨", "爱之喜悦");
    }

}

用到的依赖:pom.xml

<dependencies>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>4.3.8.RELEASEversion>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>4.3.8.RELEASEversion>
        dependency>       
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>4.3.8.RELEASEversion>
        dependency>        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aopartifactId>
            <version>4.3.8.RELEASEversion>
        dependency>        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjrtartifactId>
            <version>1.8.7version>
        dependency>
    dependencies>
    <build>
        <plugins>
        
            <plugin>
                <groupId>org.codehaus.mojogroupId>
                <artifactId>aspectj-maven-pluginartifactId>
                <version>1.8version>
                <executions>
                    <execution>
                        <goals>
                            <goal>compilegoal>
                        goals>
                    execution>
                executions>
                <configuration>
                    <complianceLevel>1.8complianceLevel>
                    <source>1.8source>
                    <target>1.8target>
                configuration>
            plugin>
        plugins>
    build>

运行结果:
工作人员已入场
有请钢琴表演
钢琴表演即将开始,请各位观众交出手机
有请小提琴表演
小提琴表演即将开始,请各位观众交出手机
观众已全部交出手机
钢琴表演开始
亚莎·海菲兹演奏钢琴曲:致爱丽斯
亚莎·海菲兹演奏完毕,刚才演奏的曲子叫:致爱丽斯
观众已全部交出手机
小提琴表演开始
霍洛维茨演奏了小提琴曲:爱之喜悦
霍洛维茨演奏完毕,刚才演奏的曲子叫:爱之喜悦

Audience.class文件

package concert;

import concert.Worker;
import org.aspectj.lang.NoAspectBoundException;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class Audience {
    private Worker worker;

    static {
        try {
            ajc$postClinit();
        } catch (Throwable var1) {
            ajc$initFailureCause = var1;
        }

    }

    public void setWorker(Worker worker) {
        this.worker = worker;
        System.out.println("工作人员已入场");
    }

    public Audience() {
    }

    @After(
        value = "piano()",
        argNames = ""
    )
    public void ajc$after$concert_Audience$1$dd71540a() {
        this.worker.sendMsg("钢琴");
    }

    @After(
        value = "violin()",
        argNames = ""
    )
    public void ajc$after$concert_Audience$2$57c630b6() {
        this.worker.sendMsg("小提琴");
    }

    @Before(
        value = "perform()",
        argNames = ""
    )
    public void ajc$before$concert_Audience$3$1cad9822() {
        this.worker.take();
    }

    @After(
        value = "finishPerform(performer, title)",
        argNames = "performer,title"
    )
    public void ajc$after$concert_Audience$4$1840cdb9(String performer, String title) {
        this.worker.broadcast(performer, title);
    }

    //Aspect提供的静态方法,返回Audience切面的一个实例,Spring即可通过factory-method属性获得该实例
    //
    public static Audience aspectOf() {
        if(ajc$perSingletonInstance == null) {
            throw new NoAspectBoundException("concert_Audience", ajc$initFailureCause);
        } else {
            return ajc$perSingletonInstance;
        }
    }

    public static boolean hasAspect() {
        return ajc$perSingletonInstance != null;
    }
}

写在最后:
Spring所支持的AOP已经可以满足很多需求,如果要求更高,可以使用AspectJ提供的更丰富的切点类型,当然需要熟悉AspectJ语法。
本文只是简单的举出了部分切点类型和通知类型,更多的类型读者可以自行尝试。欢迎留言指正,感谢您的阅读!

你可能感兴趣的:(Spring)