選擇切點
Spring是方法級別的AOP框架,而我們主要也是以某個類的某個方法作為切點,用動態代理的理論來說,就是要攔截哪個方法織入對應AOP通知。
代碼清單:打印角色接口
代碼清單:打印角色接口
package com.ssm.chapter11.aop.service; import com.ssm.chapter11.game.pojo.Role; public interface RoleService { // public void printRole(Role role); public void printRole(Role role, int sort); }
代碼清單:RoleService實現類
package com.ssm.chapter11.aop.service.impl; import org.springframework.stereotype.Component; import com.ssm.chapter11.aop.service.RoleService; import com.ssm.chapter11.game.pojo.Role; @Component public class RoleServiceImpl implements RoleService { // @Override // public void printRole(Role role) { // System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}"); // } public void printRole(Role role, int sort) { System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}"); System.out.println(sort); } }
這個類沒什么特別的,只是這個時候如果把printRole作為AOP的切點,那么用動態代理的語言就是要為類RoleServi-ceImpl生成代理對象,然后攔截printRole方法,於是可以產生各種AOP通知方法。
創建切面
選擇好了切點就可以創建切面了,對於動態代理的概念而言,它就如同一個攔截器,在Spring中只要使用@Aspect注解一個類,那么Spring IoC容器就會認為這是一個切面了
package com.ssm.chapter11.aop.aspect; import com.ssm.chapter11.aop.verifier.RoleVerifier; import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect public class RoleAspect { @DeclareParents(value = "com.ssm.chapter11.aop.service.impl.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class) public RoleVerifier roleVerifier; @Pointcut("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))") public void print() { } // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))") // @Before("execution(* com.ssm.chapter11.*.*.*.*.printRole(..)) && within(com.ssm.chapter11.aop.service.impl.*)") @Before("print()") // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..)) && args(role, sort)") public void before() { System.out.println("before ...."); } @After("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))") public void after() { System.out.println("after ...."); } @AfterReturning("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))") public void afterReturning() { System.out.println("afterReturning ...."); } @AfterThrowing("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))") public void afterThrowing() { System.out.println("afterThrowing ...."); } @Around("print()") public void around(ProceedingJoinPoint jp) { System.out.println("around before ...."); try { jp.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("around after ...."); } }

連接點
Spring是如何判斷是否需要攔截方法的,畢竟並不是所有的方法都需要使用AOP編程,這就是一個連接點的問題。在注解中定義了execution的正則表達式,Spring是通過這個正則表達式判斷是否需要攔截你的方法的,這個表達式是:
execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))
依次對這個表達式做出分析。
•execution:代表執行方法的時候會觸發。
•*:代表任意返回類型的方法。
•com.ssm.chapter11.aop.service.impl.RoleServiceImpl:代表類的全限定名。
•printRole:被攔截方法名稱。
•(..):任意的參數。
顯然通過上面的描述,全限定名為com.ssm.chapter11.aop.service.impl.RoleServiceImpl的類的printRole方法被攔截了,這樣它就按照AOP通知的規則把方法織入流程中。
execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))
依次對這個表達式做出分析。
•execution:代表執行方法的時候會觸發。
•*:代表任意返回類型的方法。
•com.ssm.chapter11.aop.service.impl.RoleServiceImpl:代表類的全限定名。
•printRole:被攔截方法名稱。
•(..):任意的參數。
顯然通過上面的描述,全限定名為com.ssm.chapter11.aop.service.impl.RoleServiceImpl的類的printRole方法被攔截了,這樣它就按照AOP通知的規則把方法織入流程中。


測試AOP
代碼清單:配置Spring bean
代碼清單:測試AOP流程
package com.ssm.chapter11.aop.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import com.ssm.chapter11.aop.aspect.RoleAspect; @Configuration @EnableAspectJAutoProxy @ComponentScan("com.ssm.chapter11.aop") public class AopConfig { @Bean public RoleAspect getRoleAspect() { return new RoleAspect(); } }
Spring還提供了XML的方式,這里就需要使用AOP的命名空間了
<?xml version='1.0' encoding='UTF-8' ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <aop:aspectj-autoproxy/> <bean id="roleAspect" class="com.ssm.chapter11.aop.aspect.RoleAspect"/> <bean id="roleService" class="com.ssm.chapter11.aop.service.impl.RoleServiceImpl"/> </beans>
無論用XML還是用Java的配置,都能使Spring產生動態代理對象,從而組織切面,把各類通知織入到流程當中
代碼清單:測試AOP流程
package com.ssm.chapter11.aop.main; import com.ssm.chapter11.aop.verifier.RoleVerifier; import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl; import org.aspectj.lang.annotation.DeclareParents; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.ssm.chapter11.aop.config.AopConfig; import com.ssm.chapter11.aop.service.RoleService; import com.ssm.chapter11.game.pojo.Role; public class Main { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class); // 使用XML使用ClassPathXmlApplicationContext作為IoC容器 // ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter11/spring-cfg3.xml"); RoleService roleService = ctx.getBean(RoleService.class); Role role = new Role(); role.setId(1L); role.setRoleName("role_name_1"); role.setNote("note_1"); RoleVerifier roleVerifier = (RoleVerifier) roleService; if (roleVerifier.verify(role)) { roleService.printRole(role, 1); } System.out.println("####################"); //測試異常通知 // role = null; // roleService.printRole(role); } }