Spring AOP(创建切面)

Spring AOP的概念以及使用方法:

Spring AOP的可以使用方式有两种,一种是使用注解,一种是使用配置文件。它的概念和术语篇幅比较长。

参考下面文章:Spring AOP

个人觉得spring AOP思想就是代理模式的思想

 

创建通知:

Spring 中的通知类型

通知类型

接口

描述

Arround

org.aopalliance.intercept.MethodInterceptor

拦截对目标对象方法调用

Before

org.springframework.aop.BeforeAdvice

在目标方法被调用之前调用

After

org.springframework.aop.AfterReturingAdvice

在目标方法被调用之后调用

Throws

org.springfrmaework.aop.ThrowsAdvice

当目标方法抛出异常时调用

 

 

例子:有个新生报到的功能,StudentService是功能接口,StudentServiceImp是StudentService接口的实现,分别为这个创建前置通知和后置通知.
流程:在新生报到前,拦截新生,将新生带到辅导员处。注册后,将新生带到宿舍安顿。

 前置通知:

在方法调用前进行拦截器的调用,这里使用Spring提供的接口MethodBeforeAdvcie,它是BeforeAdvice的子类。需要注意的是,BefroeAdvice和MethodBeforeAdvice依赖的库在Spring中没有提供,要在以下地址下载

http://mirrors.ibiblio.org/maven2/aopalliance/aopalliance/1.0/, 下载文件为aopalliance-1.0.jar

 

com.sunflower.service.StudentService接口:

public interface StudentService {
    public void regist();
}

 

com.sunflower.serviceimp.StudentService实现类:

 1 public class StudentServiceImp implements StudentService {
 2     private String name;
 3     
 4     public String getName(){
 5         return name;
 6     }
 7 
 8     public StudentServiceImp(String name) {
 9         this.name = name;
10     }
11 
12     public void regist() {
13         System.out.println(name + "同学,请到新生报到处注册!");
14     }
15 
16 }

 

拦截器:com.sunflower.advice.WelcomeAdvice:

 1 public class WelcomeAdvice implements MethodBeforeAdvice {
 2 
 3     public void before(Method arg0, Object[] arg1, Object arg2)
 4             throws Throwable {
 5         StudentServiceImp student = (StudentServiceImp)arg2;
 6         
 7         System.out.println(student.getName() + "同学,请先找到指导员");
 8     }
 9 
10 }

 before方法的第一个参数是对目标对象的指定方法进行拦截的方法名,第二个参数是方法里的参数列表,第三个参数是目标对象

 

配置文件:applicationContext.xml:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans
 3     xmlns="http://www.springframework.org/schema/beans"
 4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5     xmlns:p="http://www.springframework.org/schema/p"
 6     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 7     
 8     <!-- 目标对象 -->
 9     <bean id="studentService" class="com.sunflower.serviceimp.StudentServiceImp">
10         <constructor-arg>
11             <value>项羽</value>
12         </constructor-arg>
13     </bean>
14     
15     <!-- 通知对象 -->
16     <bean id="welcomeAdvice" class="com.sunflower.advice.WelcomeAdvice"></bean>
17     
18     <!-- 代理对象 -->
19     <bean id="studentServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
20         <!-- 代理对象要实现的接口 -->
21         <property name="proxyInterfaces">
22             <value>com.sunflower.service.StudentService</value>
23         </property>
24         
25         <!-- 需要进行代理的目标对象 -->
26         <property name="target">
27             <ref bean="studentService"/>
28         </property>
29         
30         <!-- 用到的拦截器 -->
31         <property name="interceptorNames">
32             <value>welcomeAdvice</value>
33         </property>
34         
35     </bean>
36 
37 </beans>

 关于org.springframework.aop.framework.ProxyFactoryBean的属性描述,可以查看以下文章:ProxyFactoryBean属性介绍

 

测试类:com.suflower.test.Test:

1 public class Test {
2     public static void main(String[] args) {
3         ApplicationContext context = new  ClassPathXmlApplicationContext("applicationContext.xml");
4         //使用代理对象
5         StudentService serviceProxy = (StudentService)context.getBean("studentServiceProxy");
6         serviceProxy.regist();
7     }
8 }

程序运行结果:

可以看出前置通知已经起到作用,他在注册方法regist之前进行拦截,执行自己的代码。

 

后置通知:

后置通知和前置通知的使用方法类似,不过实现的接口不同,后置通知实现org.springframework.aop.AfterReturningAdvice接口。

 

com.sunflower.advice.GoDomeAdvice:

1 public class GoDomeAdvice implements AfterReturningAdvice {
2     @Override
3     public void afterReturning(Object arg0, Method arg1, Object[] arg2,
4             Object arg3) throws Throwable {
5          StudentServiceImp student = (StudentServiceImp)arg3;
6          System.out.println(student.getName() + "同学,请到宿舍休息,下午接受学院安排");
7     }
8 }

在前面的基础上,修改配置文件applicationContext.xml:

<!--增加一个后置通知的bean-->
<!-- 后置通知对象 -->
    <bean id="goDomeAdvice" class="com.sunflower.advice.GoDomeAdvice"></bean>

…………………………

<!-- 代理对象 -->
    <bean id="studentServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
…………………………省略
<!-- 用到的拦截器 -->
        <property name="interceptorNames">
            <list>
                <value>welcomeAdvice</value>
                <!--加载后置通知-->
                <value>goDomeAdvice</value>
            </list>
        </property>
…………………………省略

</bean>

 运行结果:

可以看到,后置通知起到了作用。

以上的通知会在目标对象的所有方法执行前后执行,这样不够细粒度,如果我们需要指明对目标对象特定方法进行通知,则需要定义切入点。

 

定义切入点:

切入点决定了一个特定类的特定方法是否满足一条特定规则。如果一个方法确实符合,通知就应用到该方法上。Spring的切入点可以让我们以一种灵活的方式定义在什么地方将通知织入到我们的类中。

Spring的切入点框架的核心接口是Pointcut:
public interface Pointcut{
 ClassFilter getClassFilter();
 MethodMatcher getMethodMatcher();
}

ClassFilter接口决定了一个类是否符合通知的要求:
public interface ClassFilter{
 boolean matchers(Class clazz);
}

也可以通过方法进行过滤,通过MethodMatcher接口可以实现这个功能:
public interface MethodMatcher{
 boolean matches(Method m, class targetClass);
 public boolean isRuntime();
 public boolean matches(Method m, Class target, Object[] args);
}

 

Spring提供了Advisor,它把通知和切入点组合到一个对象中。更确切地说,PointcutAdvisor提供这些功能: 
public interface PointcutAdvisor{
 
 Pointcut getPointcut();
 Advice getAdvice();
}

可以使用Spring提供的静态切入点通知NameMatchMethodPointcutAdvisor来过滤需要进行通知的方法。

com.sunflower.advisor.RegistAdvisor:

1 public class RegistAdvisor extends NameMatchMethodPointcutAdvisor{
2     
3 }

只要继承NameMatchMethodPointcutAdvisor这个类即可。
然后修改Srping配置文件,将需要的参数设置进去:

applicationContext.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" xmlns:p="http://www.springframework.org/schema/p"
 4     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 5 
 6     <!-- 目标对象 -->
 7     <bean id="studentService" class="com.sunflower.serviceimp.StudentServiceImp">
 8         <constructor-arg>
 9             <value>项羽</value>
10         </constructor-arg>
11     </bean>
12 
13     <!-- 前置通知对象 -->
14     <bean id="welcomeAdvice" class="com.sunflower.advice.WelcomeAdvice"></bean>
15     <!-- 后置通知对象 -->
16     <bean id="goDomeAdvice" class="com.sunflower.advice.GoDomeAdvice"></bean>
17     
18     <!-- 切入点通知 -->
19     <bean id="registAdvisor" class="com.sunflower.advisor.RegistAdvisor">
20         <!-- 声明切入点 -->
21         <property name="mappedName">
22             <value>regist</value>
23         </property>
24         
25         <!-- 调用通知 -->
26         <property name="advice">
27             <ref bean="welcomeAdvice"/>
28         </property>
29         
30     </bean>
31 
32     <!-- 代理对象 -->
33     <bean id="studentServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
34         <!-- 代理对象要实现的接口 -->
35         <property name="proxyInterfaces">
36             <value>com.sunflower.service.StudentService</value>
37         </property>
38 
39         <!-- 需要进行代理的目标对象 -->
40         <property name="target">
41             <ref bean="studentService" />
42         </property>
43 
44         <!-- 用到的拦截器 -->
45         <property name="interceptorNames">
46             <list>
47                 <value>registAdvisor</value>
48             </list>
49         </property>
50 
51     </bean>
52 
53 </beans>

第18~30行为Advisor设置参数的过程,<property name="mappedName">属性是设置需要进行过滤的方法名,即切入点,<property name="advice">是设置需要调用的通知。第47行将拦截器设置为Advisor即可,其他不变。


用注解的方式来使用Spring AOP,可以参考如下文章:
Spring2.5 注解 Aspect AOP (转)

 

一颗平常心,踏踏实实,平静对待一切
原文地址:https://www.cnblogs.com/hanyuan/p/2700260.html