SpringAOP之注入AspectJ切面
来源:互联网 发布:专业网络k歌声卡 编辑:程序博客网 时间:2024/06/02 00:43
写在开头:
本文参考资料为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); } }
//定义工作人员,将作为切面的协作beanpackage 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
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="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"> <!--<bean id="piano" class="concert.PianoPerform" lazy-init="true"/>--> <bean id="worker" class="concert.Worker"/> <!--Spring需要通过静态方法aspectOf获得audience实例,Audience切面编译后的class文件附在文末--> <bean class="concert.Audience" factory-method="aspectOf"> <property name="worker" ref="worker" /><!--通过Spring把协作的bean注入到切面中--> </bean> <!--这里注意一下bean的顺序,因为在构造器切点后置通知时调用了worker的sendMsg(String)方法,所以避免出现空指针异常,咱们先把worker声明在前--> <!--如果要将piano或者violin声明在前,可以设置lazy-init="true"--> <!--所以spring是从上到下解析并实例化bean?还是解析完整个文件再实例化呢?欢迎评论区留言交流--> <bean id="piano" class="concert.PianoPerform"/> <bean id="violin" class="concert.ViolinPerform"/></beans>
//主程序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>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.7</version> </dependency> </dependencies> <build> <plugins> <!--编译aspect的插件,必须要将Audience.aj编译为class文件, 不然spring创建audience bean的时候找不到类--> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.8</version> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> <configuration> <complianceLevel>1.8</complianceLevel> <source>1.8</source> <target>1.8</target> </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;@Aspectpublic 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属性获得该实例 //<bean class="concert.Audience" factory-method="aspectOf"> 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语法。
本文只是简单的举出了部分切点类型和通知类型,更多的类型读者可以自行尝试。欢迎留言指正,感谢您的阅读!
阅读全文
6 0
- SpringAOP之注入AspectJ切面
- 4.5 注入AspectJ切面
- 注入AspectJ切面
- springAOP之aspectJ(一)
- SpringAOP入门学习一:基于注解配置切面( AspectJ)
- 面向切面的 Spring —— 如何注入 AspectJ 切面?
- 学习笔记之springAOP的aspectJ实现注意点总结
- SpringAOP应用(AspectJ)
- SpringAop-1.AspectJ起步
- SpringAOP和AspectJ详解
- springAOP面向切面编程之日志记录功能
- SpringAOP之切点和切面的深入理解
- SpringAOP面向切面
- SpringAop--切面实例
- Spring笔记之六:AOP基于@AspectJ配置切面
- AspectJ Aop 面向切面
- aspectJ切面使用
- AspectJ(面向切面)
- macOS系统下搭建Android开发环境
- 机器学习开发环境搭建配置(ML+python+pycharm)图文教程
- js 基本语法
- WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED解决方法
- 在制定字符串内删除指定字符。
- SpringAOP之注入AspectJ切面
- more than one `-Acdtrux' or `--test-label' option
- 经典动态规划之最长上升子序列
- 使用maven和springMVC项目的结构
- Runtime linking on Mac
- C++ 阻塞队列
- 网络七层模型
- 我的博客
- HDU-1074-状态压缩DP