1.AspectJ - AOP 面向切面編程是面向?qū)ο蟮囊粋€補充 在保存用戶前添加一個日志,再加上時刻的記錄,。 總之,,就是方法前后加一點業(yè)務(wù)邏輯 新建資源庫:
Preference>Java>BuildPath>UserLibraries,AddLibrary>UserLibrary
/Spring_AOP/src/yuki/spring/aop/imitate/UserService.java package yuki.spring.aop.imitate; public interface UserService { void save(); } /Spring_AOP/src/yuki/spring/aop/imitate/UserServiceImpl.java package yuki.spring.aop.imitate; public class UserServiceImpl implements UserService{ public void save(){ System.out.println("user saved..."); } } /Spring_AOP/src/yuki/spring/aop/imitate/Intercepter.java package yuki.spring.aop.imitate; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public abstract class Intercepter implements InvocationHandler { private Object target; public void setTarget(Object target) { this.target = target; } protected abstract void beforeMethod(); protected abstract void afterMethod(); @Override public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { beforeMethod(); m.invoke(target, args); afterMethod(); return null; } } /Spring_AOP/src/yuki/spring/aop/imitate/LogIntercepter.java package yuki.spring.aop.imitate; public class LogIntercepter extends Intercepter { @Override public void beforeMethod() { System.out.println("log start..."); } @Override protected void afterMethod() { System.out.println("log end..."); } } /Spring_AOP/src/yuki/spring/aop/imitate/TimeIntercepter.java package yuki.spring.aop.imitate; public class TimeIntercepter extends Intercepter { @Override protected void beforeMethod() { System.out.println("start:" + System.currentTimeMillis()); } @Override protected void afterMethod() { System.out.println("end:" + System.currentTimeMillis()); } } /Spring_AOP/src/yuki/spring/aop/imitate/ProxyTest.java package yuki.spring.aop.imitate; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { UserService service = new UserServiceImpl(); Intercepter[] intercepters = {new LogIntercepter(), new TimeIntercepter()}; for(Intercepter intercepter : intercepters){ intercepter.setTarget(service); service = (UserService) Proxy.newProxyInstance( service.getClass().getClassLoader(), service.getClass().getInterfaces(), intercepter); } service.save(); } } 上面的程序中,,兩個類繼承了實現(xiàn)InvocationHandler接口的抽象類,, 也可以說是間接地實現(xiàn)了InvocationHandler接口; 聲明為UserService接口類型的service,, 在循環(huán)中每一次接收Proxy.newProxyInstance方法的計算結(jié)果后就會改變它指向的對象。 運行結(jié)果如下: start:1409496143248 log start... user saved... log end... end:1409496143250 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 注解的方式實現(xiàn)AOP使用的是aspectj,, aspectj是專門用來產(chǎn)生動態(tài)代理的一個框架 可以使用aspectj注解的方式實現(xiàn)spring的AOP,,把這個邏輯織入到原來的邏輯里面去 引入jar:aspectjrt.jar、aspectj-weaver.jar:http://www./Code/Jar/a/aspectj.htm 在類上添加注解 @Aspect和 @Component,在方法上添加注解 @Before 切入點語法 @Before("execution(public void yuki.spring.aop.annotation" + ".UserServiceImpl.save(yuki.spring.aop.annotation.User))") 引入jar:aopalliance-.jar: http://www./Code/Jar/a/Downloadaopalliancejar.htm @Component要加在對應(yīng)的實現(xiàn)類上,,因為getBean后要獲取這個對象 /Spring_AOP/src/yuki/spring/aop/annotation/User.java package yuki.spring.aop.annotation; public class User { } /Spring_AOP/src/yuki/spring/aop/annotation/UserService.java package yuki.spring.aop.annotation; public interface UserService { void save(User user); } /Spring_AOP/src/yuki/spring/aop/annotation/UserServiceImpl.java package yuki.spring.aop.annotation; import org.springframework.stereotype.Component; @Component("userService") public class UserServiceImpl implements UserService{ public void save(User user){ System.out.println("user saved..."); } } /Spring_AOP/src/annotation.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:aop="http://www./schema/aop" xmlns:context="http://www./schema/context" xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-4.0.xsd http://www./schema/aop http://www./schema/aop/spring-aop-4.0.xsd http://www./schema/context http://www./schema/context/spring-context-4.0.xsd "> <context:annotation-config></context:annotation-config> <context:component-scan base-package="yuki.spring.aop.annotation"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> /Spring_AOP/src/yuki/spring/aop/annotation/LogIntercepter.java package yuki.spring.aop.annotation; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class LogIntercepter { @Before("execution(public void yuki.spring.aop.annotation" + ".UserServiceImpl.save(yuki.spring.aop.annotation.User))") public void beforeMethod() { System.out.println("method start..."); } } /Spring_AOP/src/yuki/spring/aop/annotation/TimeIntercepter.java package yuki.spring.aop.annotation; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class TimeIntercepter { @Before("execution(" + "public * yuki.spring.aop.annotation..*.*(..)" + ")") public void beforeMethod() { System.out.println("before:" + System.currentTimeMillis()); } @AfterReturning("execution( public * yuki.spring.aop.annotation..*.*(..) )") public void afterReturningMethod() { System.out.println("afterReturning:" + System.currentTimeMillis()); } } /Spring_AOP/src/yuki/spring/aop/annotation/PointcutIntercepter.java package yuki.spring.aop.annotation; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class PointcutIntercepter { @Pointcut("execution( public * yuki.spring.aop.annotation..*.*(..) )") public void myMethod() {} @Before("myMethod()") public void beforeMethod() { System.out.println("PointcutIntercepter::before"); } @AfterReturning("myMethod()") public void afterReturningMethod() { System.out.println("PointcutIntercepter::afterReturning"); } } /Spring_AOP/src/yuki/spring/aop/annotation/UserServiceTest.java package yuki.spring.aop.annotation; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void testSave() { @SuppressWarnings("resource") ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("annotation.xml"); UserService service = (UserService) context.getBean("userService"); service.save(new User()); context.destroy(); } } 運行結(jié)果如下: 八月 31, 2014 10:59:10 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 22:59:10 CST 2014]; root of context hierarchy 八月 31, 2014 10:59:10 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [annotation.xml] method start... PointcutIntercepter::before before:1409497152268 user saved... afterReturning:1409497152268 PointcutIntercepter::afterReturning 八月 31, 2014 10:59:12 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 22:59:10 CST 2014]; root of context hierarchy 術(shù)語解釋: JoinPoint:連接點,、切入點,在哪里把邏輯加進區(qū) PointCut:JoinPoint的集合,,可以一次性定義好多切入點 Aspect:切面,,切面類加進去的邏輯可以認為是一個切面 Advice:在這個點上建議怎么辦,比如 @Before Target:被織入邏輯的被代理對象 Weave:織入 2.切面和通知 切入點: // the execution of any public method: execution(public * *(..)) // the execution of any method with a name beginning with "set": execution(* set*(..)) // the execution of any method defined by the AccountService interface: execution(* com.xyz.service.AccountService.*(..)) // the execution of any method defined in the service package: execution(* com.xyz.service..(..)) // the execution of any method defined in the service package or a sub-package: execution(* com.xyz.service..*.*(..)) spring也定義了自己的織入點語法,,但是我們只要用AspectJ的語法就可以了 通知: Before,、AfterReturn、AfterThrowing,、After(意思是finally) Around:在ProceedingJoinPoint.proceed()前后加邏輯 如果織入點表達式相同,,可以定義Pointcut 定義方法名接收織入點表達式的值,使用時 @AfterReturning("pointcut()") /Spring_AOP/src/yuki/spring/aop/pointcut/User.java package yuki.spring.aop.pointcut; public class User { } /Spring_AOP/src/yuki/spring/aop/pointcut/UserService.java package yuki.spring.aop.pointcut; public interface UserService { void save(User user); } /Spring_AOP/src/yuki/spring/aop/pointcut/UserServiceImpl.java package yuki.spring.aop.pointcut; import org.springframework.stereotype.Component; @Component("userService") public class UserServiceImpl implements UserService{ public void save(User user){ System.out.println("user saved..."); //throw new RuntimeException("exception..."); } } /Spring_AOP/src/yuki/spring/aop/pointcut/TransactionAspect.java package yuki.spring.aop.pointcut; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class TransactionAspect { @Pointcut("execution( public * yuki.spring.aop.pointcut..*.*(..) )") public void pointcut(){} @Before("pointcut()") public void before(){ System.out.println("before"); } @AfterReturning("pointcut()") public void afterReturning(){ System.out.println("afterReturning"); } @AfterThrowing("pointcut()") public void afterThrowing(){ System.out.println("afterThrowing"); } @Around("pointcut()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("method around start..."); pjp.proceed(); System.out.println("method around end..."); } } /Spring_AOP/src/pointcut.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:aop="http://www./schema/aop" xmlns:context="http://www./schema/context" xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-4.0.xsd http://www./schema/aop http://www./schema/aop/spring-aop-4.0.xsd http://www./schema/context http://www./schema/context/spring-context-4.0.xsd "> <context:annotation-config></context:annotation-config> <context:component-scan base-package="yuki.spring.aop.pointcut"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> /Spring_AOP/src/yuki/spring/aop/pointcut/UserServiceTest.java package yuki.spring.aop.pointcut; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void testSave() { @SuppressWarnings("resource") ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("pointcut.xml"); UserService service = (UserService) context.getBean("userService"); service.save(new User()); context.destroy(); } } 運行結(jié)果如下: 八月 31, 2014 11:09:22 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:09:22 CST 2014]; root of context hierarchy 八月 31, 2014 11:09:22 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [pointcut.xml] method around start... before user saved... method around end... afterReturning 八月 31, 2014 11:09:24 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:09:22 CST 2014]; root of context hierarchy 可以實現(xiàn)聲明式的異常管理,, struts2已經(jīng)實現(xiàn)了聲明式的異常管理,,這里略過通知執(zhí)行的先后順序 3.cglib 如果被代理的類實現(xiàn)了接口, 就會使用JDK自帶的Proxy和InvocationHandler來實現(xiàn)代理 當被代理的類沒有實現(xiàn)接口,, 它會用cglib直接操作二進制碼的形式來產(chǎn)生代理的代碼 引入jar:cglib-2.2.jar:http://www./Code/Jar/c/Downloadcglib22jar.htm /Spring_AOP/src/yuki/spring/aop/cglib/UserService.java package yuki.spring.aop.cglib; import org.springframework.stereotype.Component; @Component public class UserService { public void save(){ System.out.println("user saved..."); } } /Spring_AOP/src/yuki/spring/aop/cglib/CglibAspect.java package yuki.spring.aop.cglib; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class CglibAspect { @Pointcut("execution( public * yuki.spring.aop.cglib..*.*(..) )") public void pointcut(){} @Around("pointcut()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("method around start..."); pjp.proceed(); System.out.println("method around end..."); } } /Spring_AOP/src/cglib.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:aop="http://www./schema/aop" xmlns:context="http://www./schema/context" xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-4.0.xsd http://www./schema/aop http://www./schema/aop/spring-aop-4.0.xsd http://www./schema/context http://www./schema/context/spring-context-4.0.xsd "> <context:annotation-config></context:annotation-config> <context:component-scan base-package="yuki.spring.aop.cglib"></context:component-scan> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> /Spring_AOP/src/yuki/spring/aop/cglib/UserServiceTest.java package yuki.spring.aop.cglib; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void testSave() { @SuppressWarnings("resource") ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("cglib.xml"); UserService service = (UserService) context.getBean("userService"); System.out.println(service.getClass()); service.save(); context.destroy(); } } 運行結(jié)果如下: 八月 31, 2014 11:14:17 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:14:17 CST 2014]; root of context hierarchy 八月 31, 2014 11:14:17 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [cglib.xml] class yuki.spring.aop.cglib.UserService$$EnhancerBySpringCGLIB$$b8ea6837 method around start... user saved... method around end... 八月 31, 2014 11:14:19 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:14:17 CST 2014]; root of context hierarchy 4.xml:AOP pointcut可以聲明在aspect的里面或外面 eclipse:從源碼視圖切換到設(shè)計視圖
在執(zhí)行UserService.save()時,,發(fā)現(xiàn)符合配置的切入點表達式 對應(yīng)的是LogAspect.before(),于是先執(zhí)行before,,然后save() 可以直接指定pointcut,,也可以在外部指定然后再引用它 如果使用第三方類的切面類邏輯,那么就必須要使用xml配置的方式 /Spring_AOP/src/yuki/spring/aop/xml/UserService.java package yuki.spring.aop.xml; import org.springframework.stereotype.Component; @Component("userService") public class UserService { public void save(){ System.out.println("user saved..."); } } /Spring_AOP/src/yuki/spring/aop/xml/LogAspect.java package yuki.spring.aop.xml; public class LogAspect { public void before() { System.out.println("method start..."); } } /Spring_AOP/src/xml.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:aop="http://www./schema/aop" xmlns:context="http://www./schema/context" xmlns="http://www./schema/beans" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://www./schema/beans http://www./schema/beans/spring-beans-4.0.xsd http://www./schema/aop http://www./schema/aop/spring-aop-4.0.xsd http://www./schema/context http://www./schema/context/spring-context-4.0.xsd "> <context:annotation-config></context:annotation-config> <context:component-scan base-package="yuki.spring.aop.xml"></context:component-scan> <bean id="logAspect" class="yuki.spring.aop.xml.LogAspect"></bean> <!-- <aop:config> <aop:pointcut id="servicePointcut" expression="execution( public * yuki.spring.aop.xml..*.*(..) )" /> <aop:aspect id="logAspect" ref="logAspect"> <aop:before method="before" pointcut-ref="servicePointcut"/> </aop:aspect> </aop:config> --> <aop:config> <aop:aspect id="logAspect" ref="logAspect"> <aop:before method="before" pointcut="execution( public * yuki.spring.aop.xml..*.*(..) )"/> </aop:aspect> </aop:config> </beans> /Spring_AOP/src/yuki/spring/aop/xml/UserServiceTest.java package yuki.spring.aop.xml; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class UserServiceTest { @Test public void testSave() { @SuppressWarnings("resource") ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xml.xml"); UserService service = (UserService) context.getBean("userService"); service.save(); context.destroy(); } } 運行結(jié)果如下: 八月 31, 2014 11:19:01 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:19:01 CST 2014]; root of context hierarchy 八月 31, 2014 11:19:01 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [xml.xml] method start... user saved... 八月 31, 2014 11:19:02 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@1637f22: startup date [Sun Aug 31 23:19:01 CST 2014]; root of context hierarchy 5.tomcat debug的熱部署 在tomcat的jdk虛擬機參數(shù)中添加 -Dcom.sun.management.jmxremote=true 如果修改配置文件,,使用了自定義標簽的jsp頁面,,修改了注解,等等情況:還是要重啟服務(wù)器的 在方法內(nèi)部修改代碼,,不用重啟服務(wù)器,,這已經(jīng)是很大的便捷了, 有興趣的小伙伴們?nèi)パ芯抗δ芨鼜姶蟮臒岵渴鸢?。,。?!?/span> 目錄結(jié)構(gòu):
本文參考了[尚學堂馬士兵_Spring_AOP]的公開課程 更多好文請關(guān)注:http://www.cnblogs.com/kodoyang/ >*_*< kongdongyang 2014/8/31 |
|
來自: 藏經(jīng)閣_蒼穹 > 《待分類》