Spring实现AOP的方式

来源:互联网 发布:球球大作战最新源码 编辑:程序博客网 时间:2024/05/17 05:50
原文地址:Spring实现AOP的方式作者:美舞映煌

一、经典的基于代理的AOP
1、Spring支持五种类型的通知:
(1)Before(前) org.apringframework.aop.MethodBeforeAdvice
(2)After-returning(返回后)org.springframework.aop.AfterReturningAdvice
(3)After-throwing(抛出后) org.springframework.aop.ThrowsAdvice
(4)Arround(周围) org.aopaliance.intercept.MethodInterceptor
(5)Introduction(引入)org.springframework.aop.IntroductionInterceptor
2、步骤:
(1)创建通知:实现这几个接口,把其中的方法实现了
(2)定义切点和通知者:在Spring配制文件中配置这些信息
(3)使用ProxyFactoryBean来生成代理
3、具体做法:
(1)创建通知:
a、接口Sleepable:
package com.makocn.aop.spring;
public interface Sleepable {
 void sleep();
}
b、人类Human:
package com.makocn.aop.spring;

public class Human implements Sleepable {
 public void sleep() {
  System.out.println("睡觉了!梦中自有颜如玉!");
 }
}
c、拦截类SleepHelper
package com.makocn.aop.spring;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;

public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice {
 public void before(Method mtd, Object[] arg1,Object arg2) throws Throwable {
  System.out.println("通常情况下睡觉之前要脱衣服!");
 }
 public void afterReturning(Object arg0, Methodarg1, Object[] arg2, Object arg3) throws Throwable {
  System.out.println("起床后要先穿衣服!");
 }
}
d、spring配置文件applicationContext0.xml
 <bean id="human"class="com.makocn.aop.spring.Human" />
 <bean id="sleepHelper"class="com.makocn.aop.spring.SleepHelper" />
(2)定义切点和通知者:
定义切点的常用的两种方式:1)使用正则表达式 2)使用AspectJ表达式。这里用正则表达式
在spring配置文件里添加:
 <!--使用org.springframework.aop.support.JdkRegexpMethodPointcut来定义正则表达式切点-->
 <bean id="sleepPointcut"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
  <propertyname="pattern" value=".*sleep" />
 </bean>
 <!--切点定义了故事发生地点,故事发生时间及故事的内容,就是通知。通过org.springframework.aop.support.DefaultPointcutAdvisor把通知跟切点结合起来-->
 <bean id="sleepHelperAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor">
  <propertyname="advice" ref="sleepHelper" />
  <propertyname="pointcut" ref="sleepPointcut" />
 </bean>
(3)使用ProxyFactoryBean来生成代理
切入点和通知都配置完成,接下来该调用ProxyFactoryBean产生代理对象,可以把它转换为proxyInterfaces中指定的实现该interface的代理对象。在spring配置文件里添加:
 <bean id="humanProxy"class="org.springframework.aop.framework.ProxyFactoryBean">
  <propertyname="target" ref="human" />
  <propertyname="interceptorNames" value="sleepHelperAdvisor"/>
  <propertyname="proxyInterfaces" value="com.makocn.aop.spring.Sleepable"/>
 </bean>
(4)测试类Test:
package com.makocn.aop.spring;
importorg.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class Test {
 public static void main(String[] args) {
  ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext0.xml");
  Sleepable sleeper = (Sleepable)appCtx.getBean("humanProxy");
  sleeper.sleep();
 }
}
(5)测试结果:
通常情况下睡觉之前要脱衣服!
睡觉了!梦中自有颜如玉!
起床后要先穿衣服!
applicationContext0.xml文件全部内容:
<?xml version="1.0"encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTDBEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> 
 <bean id="human"class="com.makocn.aop.spring.Human" />
 <bean id="sleepHelper"class="com.makocn.aop.spring.SleepHelper" />
 <bean id="sleepPointcut"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
  <propertyname="pattern" value=".*sleep" />
 </bean>
 <bean id="sleepHelperAdvisor"class="org.springframework.aop.support.DefaultPointcutAdvisor">
  <propertyname="advice" ref="sleepHelper" />
  <propertyname="pointcut" ref="sleepPointcut" />
 </bean>
 <bean id="humanProxy"class="org.springframework.aop.framework.ProxyFactoryBean">
  <propertyname="target" ref="human" />
  <propertyname="interceptorNames" value="sleepHelperAdvisor"/>
  <propertyname="proxyInterfaces" value="com.makocn.aop.spring.Sleepable"/>
 </bean>
</beans>
上面配置切点跟通知有点麻烦,Spring提供了一种自动代理的功能,让切点跟通知自动进行匹配
applicationContext1.xml文件内容:
<?xml version="1.0"encoding="gb2312"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTDBEAN//EN"
 "http://www.springframework.org/dtd/spring-beans.dtd">
<beans> 
 <bean id="human"class="com.makocn.aop.spring.Human" />
 <bean id="sleepHelper"class="com.makocn.aop.spring.SleepHelper" />
 <bean id="sleepAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  <propertyname="advice" ref="sleepHelper" />
  <propertyname="pattern" value=".*sleep" />
 </bean>
 <!--上面配置切点跟通知有点麻烦,Spring提供了一种自动代理的功能,让切点跟通知自动进行匹配-->
 <beanclass="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
测试类Test:
package com.makocn.aop.spring;
importorg.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class Test {
 public static void main(String[] args) {
  ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext1.xml");
  Sleepable sleeper =(Sleepable)appCtx.getBean("human");
  sleeper.sleep();
 }
}
二、@AspectJ注解驱动的切面
1、拦截类AspectSleepHelper :
package com.makocn.aop.spring;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AspectSleepHelper {
 public AspectSleepHelper() {
 }
 @Pointcut("execution(* *.sleep())")
 public void sleeppoint() {
 }
 @Before("sleeppoint()")
 public void beforeSleep() {
  System.out.println("睡觉前要脱衣服!");
 }
 @AfterReturning("sleeppoint()")
 public void afterSleep() {
  System.out.println("睡醒了要穿衣服!");
 }
}
用@Aspect的注解来标识切面,注意不要把它漏了,否则Spring创建代理的时候会找不到它,@Pointcut注解指定了切点,@Before和@AfterReturning指定了运行时的通知,注意的是要在注解中传入切点的名称
2、Spring配置文件:
<?xml version="1.0"encoding="gb2312"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
       http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
 <aop:aspectj-autoproxy/><!--Spring就能够自动扫描被@Aspect标注的切面 -->
 <bean id="human"class="com.makocn.aop.spring.Human" />
 <bean id="sleepHelper"class="com.makocn.aop.spring.AspectSleepHelper"/>
</beans>
3、测试类Test:
package com.makocn.aop.spring;
importorg.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class Test {
 public static void main(String[] args) {
  ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext2.xml");
  Sleepable sleeper = (Sleepable)appCtx.getBean("human");
  sleeper.sleep();
 }
}

三、使用Spring来定义纯粹的POJO切面
前面我们用到了<aop:aspectj-autoproxy/>标签,Spring在aop的命名空间里面还提供了其他的配置元素:
<aop:advisor> 定义一个AOP通知者
<aop:after> 后通知
<aop:after-returning> 返回后通知
<aop:after-throwing> 抛出后通知
<aop:around> 周围通知
<aop:aspect>定义一个切面
<aop:before>前通知
<aop:config>顶级配置元素,类似于<beans>这种东西
<aop:pointcut>定义一个切点
1、拦截类POJOSleepHelper
package com.makocn.aop.spring;
public class POJOSleepHelper {
 public void beforeSleep() {
  System.out.println("通常情况下睡觉之前要脱衣服!");
 }
 public void afterSleep() {
  System.out.println("起床后要先穿衣服!");
 }

}
2、Spring的配置applicationContext3.xml文件:
<?xml version="1.0"encoding="gb2312"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="
       http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
 <bean id="human"class="com.makocn.aop.spring.Human" />
 <bean id="sleepHelper"class="com.makocn.aop.spring.POJOSleepHelper"/>
 <aop:config>
  <aop:aspectref="sleepHelper">
   <aop:beforemethod="beforeSleep" pointcut="execution(* *.sleep(..))"/>
   <aop:aftermethod="afterSleep" pointcut="execution(* *.sleep(..))"/>
  </aop:aspect>
 </aop:config>
</beans>
3、测试类
package com.makocn.aop.spring;
importorg.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.context.ApplicationContext;
public class Test {
 public static void main(String[] args) {
  ApplicationContext appCtx = newClassPathXmlApplicationContext("applicationContext3.xml");
  Sleepable sleeper = (Sleepable)appCtx.getBean("human");
  sleeper.sleep();
 }
}

四、注入式AspectJ切面
该方式通过Spring集成AspectJ;AspectJ采用编译期织入和类加载期织入的方式织入切面,是语言级的AOP实现,提供了完备的AOP支持。它用AspectJ语言定义切面,在编译期或类加载期将切面织入到Java类中。

因需另外搭建具体环境,具体实现可查看网上例子。

原创粉丝点击