Spring AOP入门实例,springaop入门,Spring AOP框架
Spring AOP入门实例,springaop入门,Spring AOP框架
Spring AOP框架可以方便的实现面向方面编程。面向方面编程通俗的将就是可以在不改变原方法代码的情况下,改变原方法的执行,给方法添加额外的执行,例如为方法添加日志,为方法添加事务等等。
在Spring AOP中有4中不同的advice,分别为:
Before advice – 在方法执行之前执行After returning advice – 在方法顺利执行完毕时执行After throwing advice – 在方法执行结束抛出异常时执行Around advice – 在方法的执行前后,抛出异常时都可以注入方法,是上面三种切入点的综合下面我们通过一个既简单的例子看spring aop是如何工作的:
首先我们需要创建一个maven项目,在pom.xml中添加如下依赖项:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.0.RC2</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2.2</version> </dependency>
然后我们创建一个简单的类来作为spring aop切入的对象。
package cn.outofmemory.hellospring.aop;public class BookService { public void returnBook() { System.out.println("return book"); } public String getBook(String isbn) { return "getBook " + isbn; } public void clearBook() { throw new RuntimeException("throw exception method"); }}
然后在src/main/resources目录下新建spring.xml配置bean:
<?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-3.0.xsd"> <bean id="bookService" class="cn.outofmemory.hellospring.aop.BookService"> </bean></beans>
在上面的步骤中还没有涉及到AOP,我们准备了AOP切入的对象BookService类,下面正式进入AOP阶段:
我们先试试Before advice
Before advice会在方法执行之前执行,我们需要创建一个从MethodBeforeAdvice接口继承的类,并实现它的before方法:
package cn.outofmemory.hellospring.aop;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class BeforeAspect implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("BeforeAspect working.."); }}
下面我们在spring.xml文件中配置BeforeAspect,并添加一个代理用来代理bookService。
<?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-3.0.xsd"> <bean id="bookService" class="cn.outofmemory.hellospring.aop.BookService"> </bean> <bean id="beforeAspect" class="cn.outofmemory.hellospring.aop.BeforeAspect" /> <bean id="bookServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="bookService" /> <property name="interceptorNames"> <list> <value>beforeAspect</value> </list> </property> </bean></beans>
现在我们在spring的配置文件中配置了beforeAspect的实例,并且创建了一个bookService的代理bookServiceProxy。
下面我们在App.java中使用代理类看下输出:
package cn.outofmemory.hellospring.aop;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;/** * Hello world! * */public class App { public static void main( String[] args ) { ApplicationContext appContext = new ClassPathXmlApplicationContext("spring.xml"); BookService service = (BookService)appContext.getBean("bookServiceProxy"); String book = service.getBook("test isbn"); System.out.println(String.format("getBook %s", book)); service.returnBook(); //service.clearBook(); }}
输出:
BeforeAspect working..getBook getBook test isbnBeforeAspect working..return book
可以看到在方法执行之前,都执行了beforeAspect中定义的方法。
再看下after returning advice
顾名思义,after returning是在方法执行之后执行的,我们来实现一个AfterReturningAdvice。
如下代码:
package cn.outofmemory.hellospring.aop;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class AfterReturningAspect implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { String msg = String.format("%s complete", arg1.getName()); System.out.println(msg); }}
需要在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-3.0.xsd"> <bean id="bookService" class="cn.outofmemory.hellospring.aop.BookService"> </bean> <bean id="beforeAspect" class="cn.outofmemory.hellospring.aop.BeforeAspect" /> <bean id="afterAspect" class="cn.outofmemory.hellospring.aop.AfterReturningAspect" /> <bean id="bookServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="bookService" /> <property name="interceptorNames"> <list> <value>beforeAspect</value> <value>afterAspect</value> </list> </property> </bean></beans>
然后再次执行项目会输入如下内容:
BeforeAspect working..getBook completegetBook getBook test isbnBeforeAspect working..return bookreturnBook complete
可以看到在每个方法执行完之后打印出了xxx complete
After throwing advice
After throwing advice是在方法抛出异常时截获并执行一段代码,需要实现org.springframework.aop.ThrowsAdvice接口:
package cn.outofmemory.hellospring.aop;import org.springframework.aop.ThrowsAdvice;public class AfterThrowsAspect implements ThrowsAdvice { public void afterThrowing(RuntimeException e) throws Throwable { System.out.println("error occor : Throw exception!"); }}
需要修改下bean的配置文件:
<?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-3.0.xsd"> <bean id="bookService" class="cn.outofmemory.hellospring.aop.BookService"> </bean> <bean id="beforeAspect" class="cn.outofmemory.hellospring.aop.BeforeAspect" /> <bean id="afterAspect" class="cn.outofmemory.hellospring.aop.AfterReturningAspect" /> <bean id="afterThrowsAspect" class="cn.outofmemory.hellospring.aop.AfterThrowsAspect" /> <bean id="bookServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="bookService" /> <property name="interceptorNames"> <list> <value>beforeAspect</value> <value>afterAspect</value> <value>afterThrowsAspect</value> </list> </property> </bean></beans>
然后在App.java中调用service.clearBook();
方法,可以看到如下输入:
BeforeAspect working..getBook completegetBook getBook test isbnBeforeAspect working..return bookreturnBook completeBeforeAspect working..error occor : Throw exception!Exception in thread "main" java.lang.RuntimeException: throw exception method at cn.outofmemory.hellospring.aop.BookService.clearBook(BookService.java:16) at cn.outofmemory.hellospring.aop.BookService$$FastClassByCGLIB$$6cb0d166.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625) at cn.outofmemory.hellospring.aop.BookService$$EnhancerByCGLIB$$19ce7920.clearBook(<generated>) at cn.outofmemory.hellospring.aop.App.main(App.java:22)
以上输出说明在方法抛出异常时,aop截获了这个异常并输出了error occor : Throw exception!
最后我们看下Around advice
Around advice整合了所有其他的advice,可以任意控制是否要在方法的前后或者有异常发生时来截获方法的执行。他需要实现MethodInterceptor接口。
在around方法中需要通过调用methodInvocation.proceed();
来调用被代理类的方法,否则被代理类的方法就不会执行,也就是说我们可以通过这种方法完全改变方法的执行。
package cn.outofmemory.hellospring.aop;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;public class AroundAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { System.out.println("AroundAspect method call start .."); try { // 执行被代理对象的方法 Object result = methodInvocation.proceed(); // 方法成功执行,和AfterReturningAdvice相同 System.out.println("AroundAspect method call complete!"); return result; } catch (RuntimeException ex) { // 方法执行出异常, System.out.println("AroundAspect : Throw exception!"); throw ex; } }}
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-3.0.xsd"> <bean id="bookService" class="cn.outofmemory.hellospring.aop.BookService"> </bean> <bean id="beforeAspect" class="cn.outofmemory.hellospring.aop.BeforeAspect" /> <bean id="afterAspect" class="cn.outofmemory.hellospring.aop.AfterReturningAspect" /> <bean id="afterThrowsAspect" class="cn.outofmemory.hellospring.aop.AfterThrowsAspect" /> <bean id="aroundAspect" class="cn.outofmemory.hellospring.aop.AroundAspect" /> <bean id="bookServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="bookService" /> <property name="interceptorNames"> <list> <value>aroundAspect</value> </list> </property> </bean></beans>
运行程序,得到如下输出:
AroundAspect method call start ..AroundAspect method call complete!getBook getBook test isbnAroundAspect method call start ..return bookAroundAspect method call complete!AroundAspect method call start ..AroundAspect : Throw exception!Exception in thread "main" java.lang.RuntimeException: throw exception method at cn.outofmemory.hellospring.aop.BookService.clearBook(BookService.java:16) at cn.outofmemory.hellospring.aop.BookService$$FastClassByCGLIB$$6cb0d166.invoke(<generated>) at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:692) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at cn.outofmemory.hellospring.aop.AroundAspect.invoke(AroundAspect.java:13) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625) at cn.outofmemory.hellospring.aop.BookService$$EnhancerByCGLIB$$244315da.clearBook(<generated>) at cn.outofmemory.hellospring.aop.App.main(App.java:22)
总结: 本文只是spring aop的入门,我们在配置文件中为一个servic配置了代理,然后实验了4中不同的切入方式。
您可以下载本文相关的源码。
用户点评