笔记12 注入AspectJ切面

虽然Spring AOP能够满足许多应用的切面需求,但是与AspectJ相比, Spring AOP 是一个功能比较弱的AOP解决方案。AspectJ提供了Spring AOP所不能支持的许多类型的切点。

但是精心设计且有意义的切面很可能依赖其他类来完成它们的工作。 如果在执行通知时,切面依赖于一个或多个类,我们可以在切面内部 实例化这些协作的对象。但更好的方式是,我们可以借助Spring的依 赖注入把bean装配进AspectJ切面中。

我们为演出创建一个新切面。具体来讲,我们以切面的方式创建一个评论员的角色,他会观看演出并且会在演出之后提 供一些批评意见。

在此我们给出完整的代码。首先必须为myeclipse安装AspectJ插件,可以参考:https://blog.csdn.net/qq_35592011/article/details/71602026,安装完成后创建一个AspectJ项目。

1.表演接口Performance.java

1 package concert4;
2 
3 public interface Performance {
4     public void perform();
5 }

2.表演实现类Classcial.java

 1 package concert4;
 2 
 3 public class Classcial implements Performance {
 4 
 5     @Override
 6     public void perform() {
 7         // TODO Auto-generated method stub
 8         System.out.println("我是古典音乐会!");
 9     }
10 
11 }

3.观众类(切面)Audience.java

 1 package concert4;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 public class Audience {
 6 
 7     // ProceedingJoinPoint作为参数。
 8     // 这个对象是必须要有的,因为 你要在通知中通过它来调用被通知的方法。
 9     // 通知方法中可以做任何的 事情,当要将控制权交给被通知的方法时,它需要调 用ProceedingJoinPoint的proceed()方法。
10     public void watchPerformance(ProceedingJoinPoint jp) {
11         try {
12             System.out.println("Silencing cell phone");
13             System.out.println("Taking seats");
14             jp.proceed();
15             System.out.println("CLAP CLAP CLAP");
16         } catch (Throwable e) {
17             System.out.println("Demanding a refund");
18         }
19     }
20 }

4.附加表演接口Encoreable.java

1 package concert4;
2 
3 public interface Encoreable {
4     void performEncore();
5 }

5.附加表演实现类DefaultEncoreable.java

 1 package concert4;
 2 
 3 public class DefaultEncoreable implements Encoreable {
 4 
 5     @Override
 6     public void performEncore() {
 7         // TODO Auto-generated method stub
 8         System.out.println("川剧变脸");
 9     }
10 
11 }

6.创建评论切面CriticAspect.java

CriticAspect的主要职责是在表演结束后为表演发表评论。其中的performance()切点匹配perform()方法。当它 与after()returning通知一起配合使用时,我们可以让该切面在 表演结束时起作用。

需要注意的是整个过程并不是评论员自己发表评论,实际 上,CriticAspect与一个CriticismEngine对象相协作,在表 演结束时,调用该对象的getCriticism()方法来发表一个苛刻的 评论。为了避免CriticAspect和CriticismEngine之间产生不 必要的耦合,我们通过Setter依赖注入为CriticAspect设 置CriticismEngine。下图展示了此关系:

 1 package concert4;
 2 
 3 public aspect CriticAspect {
 4     public CriticAspect(){}
 5     pointcut performance():execution(* perform(..));
 6     after()returning :performance(){
 7         System.out.println("--------------评论----------------");
 8         System.out.println(criticismEngine.getCriticism());
 9         System.out.println("----------------------------------");
10     }
11     
12     private CriticismEngine criticismEngine;
13     
14     public void setCriticismEngine(CriticismEngine criticismEngine){
15         this.criticismEngine=criticismEngine;
16     }
17 }

7.创建评论员接口CriticismEngine.java

1 package concert4;
2 
3 public interface CriticismEngine {
4     public String getCriticism();
5 }

8.实现评论员接口CriticismEngineTmpl.java(要注入到CriticAspect中的CriticismEngine实现

 1 package concert4;
 2 
 3 public class CriticismEngineTmpl implements CriticismEngine {
 4 
 5     private String[] criticismPool;
 6 
 7     public void setCriticismPool(String[] criticismPool) {
 8         this.criticismPool = criticismPool;
 9     }
10 
11     public CriticismEngineTmpl() {
12     }
13 
14     @Override
15     public String getCriticism() {
16         // TODO Auto-generated method stub
17         int i = (int) (Math.random() * criticismPool.length);
18         return criticismPool[i];
19     }
20 
21 }

CriticismEngineImpl实现了CriticismEngine接口,通过从 注入的评论池中随机选择一个苛刻的评论。要将这个类在XML文档中声明为一个bean。

9.XML配置文件

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xmlns:aop="http://www.springframework.org/schema/aop"
 5     xmlns:tx="http://www.springframework.org/schema/tx"
 6     xmlns:context="http://www.springframework.org/schema/context"
 7     xmlns:c="http://www.springframework.org/schema/c"
 8     xsi:schemaLocation="
 9    http://www.springframework.org/schema/beans
10    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
11    http://www.springframework.org/schema/aop
12    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
13    http://www.springframework.org/schema/tx
14    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
15    http://www.springframework.org/schema/context     
16    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
17            
18         <bean class="concert4.Classcial"></bean>
19         <bean id="audience" class="concert4.Audience"></bean>
20         <bean id="criticismEngine" class="concert4.CriticismEngineTmpl">
21             <property name="criticismPool">
22                 <list>
23                     <value>不好</value>
24                     <value>很不好</value>
25                     <value>非常不好</value>
26                 </list>
27             </property>
28         </bean>
29         <bean class="concert4.CriticAspect" factory-method="aspectOf">
30             <property name="criticismEngine" ref="criticismEngine"></property>
31         </bean>
32            <aop:config>
33                    <aop:aspect ref="audience">
34                        <aop:pointcut expression="execution(* concert4.Performance.perform(..))" id="performance"/>
35                        <aop:around method="watchPerformance" pointcut-ref="performance"/>
36                        <aop:declare-parents types-matching="concert4.Performance+" 
37                                             implement-interface="concert4.Encoreable" 
38                                             default-impl="concert4.DefaultEncoreable"/>
39                    </aop:aspect>
40            </aop:config>
41    </beans>

  需要注意的是,在为CriticAspect装配CriticismEngineImple之前,我们必须清楚AspectJ切面根本不需要 Spring就可以织入到我们的应用中。如果想使用Spring的依赖注入为 AspectJ切面注入协作者,那我们就需要在Spring配置中把切面声明为 一个Spring配置中的<bean>。

  但是在配置过程中使用了特殊的factorymethod属性。通常情况下,Spring bean由Spring容器初始化,但是 AspectJ切面是由AspectJ在运行期创建的。等到Spring有机会 为CriticAspect注入CriticismEngine时,CriticAspect已 经被实例化了。 因为Spring不能负责创建CriticAspect,那就不能在 Spring中简单 地把CriticAspect声明为一个bean。我们需要一种方式为 Spring获得已经由AspectJ创建的CriticAspect实例的句柄,从而可 以注入CriticismEngine。的AspectJ切面都提供了一 个静态的aspectOf()方法,该方法返回切面的一个单例。所以为了 获得切面的实例,我们必须使用factory-method来调 用asepctOf()方法而不是调用CriticAspect的构造器方法。 

  简而言之,Spring不能像之前那样使用<bean>声明来创建一 个CriticAspect实例——它已经在运行时由AspectJ创建完成了。 Spring需要通过aspectOf()工厂方法获得切面的引用,然后像 <bean>元素规定的那样在该对象上执行依赖注入。 

10.测试类ConcertTest.java

 1 package concert4;
 2 
 3 import org.junit.Test;
 4 import org.junit.runner.RunWith;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 8 
 9 @RunWith(SpringJUnit4ClassRunner.class)
10 // @ContextConfiguration(classes = concert3.ConcertConfig.class)
11 @ContextConfiguration("classpath:ConcertConfig6.xml")
12 public class ConcertTest {
13     @Autowired
14     public Performance p;
15     @Autowired
16     public Encoreable en;
17 
18     @Test
19     public void test() {
20 
21         p.perform();
22         System.out.println("-----------------------------");
23         System.out.println("自己创建对象调用");
24         en.performEncore();
25         System.out.println("-----------------------------");
26         System.out.println("通过Performance对象调用“新方法”");
27         Encoreable e = (Encoreable) p;
28         e.performEncore();
29     }
30 }

11.结果(有疑问!!!!!!!!!!)

原文地址:https://www.cnblogs.com/lyj-gyq/p/8903878.html