package com.gcg.spring.aoptest; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 定义切面 * * @author * */ @Component("aspect") @Aspect public class CheckAspect { /** * 定义切入点(Pointcut),Pointcut的名称就是allSaveMethod, 此方法不能有参数和返回值,仅是个标识。 * Pointcut的内容——"execution(*, save*(..))", 是个表达式, 描述哪些对象的哪些方法(订阅Joinpoint) * */ @Pointcut("execution(* save*(..)) || execution(* del*(..))") private void allSaveMethod() { System.out.println("========aspectinvoke======"); }; /* * 定义通知advice(before型),标识在哪个切入点 (allSaveMethod),织入(weaver)此方法 */ @Before("allSaveMethod()") public void checkUser() { System.out.println("=======CheckAspect.checkUser()==========="); } }
package com.gcg.spring.aoptest; public interface UserManger { public void delUser(int id) ; public String findUser(int id); public void saveUser(String username, String password); public void updateUser(int id) ; } package com.gcg.spring.aoptest; import org.springframework.stereotype.Component; @Component("userManager") public class UserManagerImpl implements UserManger { public void delUser(int id) { System.out.println("=====UserManagerImpl.delUser()==========="); } public String findUser(int id) { System.out.println("=====UserManagerImpl.findUser()==========="); return null; } public void saveUser(String username, String password) { System.out.println("=====UserManagerImpl.saveUser()==========="); } public void updateUser(int id) { System.out.println("=====UserManagerImpl.updateUser()==========="); } }
<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd" > <context:component-scan base-package="com.gcg.spring.entity ,com.gcg.spring.aoptest" /> <aop:aspectj-autoproxy/> <!-- <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> <bean id="boss" class="com.gcg.spring.entity.Boss"> <property name="car" ref="car"/> <property name="office" ref="office" /> </bean> <bean id="office" class="com.gcg.spring.entity.Office"> <property name="officeNo" value="002"/> </bean> <bean id="car" class="com.gcg.spring.entity.Car" scope="singleton"> <property name="brand" value=" 红旗 CA72"/> <property name="price" value="2000"/> </bean> <aop:aspectj-autoproxy/> <bean id="checkAspect" class="com.gcg.spring.aoptest.CheckAspect" />--> </beans>
package com.gcg.spring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.gcg.spring.aoptest.UserManger; public class AOPTest { // userManager.saveUser("hhe" ,"eee"); // userManager.delUser(1); // userManager.updateUser(1); public static void main(String[] args) { String[] locations = {"applicationContext.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(locations); UserManger userManager = (UserManger)ctx.getBean("userManager"); System.out.println(userManager); userManager.saveUser("gcg", "gcg"); userManager.delUser(1); userManager.findUser(1); userManager.updateUser(1); } } package com.gcg.spring.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.gcg.spring.entity.Boss; public class AnnoIocTest { public static void main(String[] args) { String[] locations = {"applicationContext.xml"}; ApplicationContext ctx = new ClassPathXmlApplicationContext(locations); Boss boss = (Boss) ctx.getBean("boss"); System.out.println(boss); } } <aop:config> <!-- 配置切面appect , ref切面类 --> <aop:aspect id="check" ref="checkAspect"> <!-- 配置切入点pointcut, 定义一个表达式 --> <aop:pointcut id="allSaveMethod" expression="execution(* com.manager.impl.UserManagerImpl.save*(..))"/> <!-- 设置before advice, 用checkAspect中的一个方法,并定位到相位的切入点pointcut --> <aop:before method="checkUser" pointcut-ref="allSaveMethod"/> </aop:aspect> </aop:config>
Spring AOP 用户可能会经常使用 execution
pointcut designator。执行表达式的格式如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *
,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 *
通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:()
匹配了一个不接受任何参数的方法, 而 (..)
匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*)
匹配了一个接受一个任何类型的参数的方法。 模式 (*,String)
匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。 请参见AspectJ编程指南的 Language Semantics 部分。
下面给出一些常见切入点表达式的例子。
-
任意公共方法的执行:
execution(public * *(..))
-
任何一个以“set”开始的方法的执行:
execution(* set*(..))
-
AccountService
接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
-
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
-
定义在service包或者子包里的任意方法的执行:
execution(* com.xyz.service..*.*(..))
-
在service包里的任意连接点(在Spring AOP中只是方法执行) :
within(com.xyz.service.*)
-
在service包或者子包里的任意连接点(在Spring AOP中只是方法执行) :
within(com.xyz.service..*)
-
实现了
AccountService
接口的代理对象的任意连接点(在Spring AOP中只是方法执行) :this(com.xyz.service.AccountService)
'this'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得代理对象可以在通知体内访问到的部分。
-
实现了
AccountService
接口的目标对象的任意连接点(在Spring AOP中只是方法执行) :target(com.xyz.service.AccountService)
'target'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得目标对象可以在通知体内访问到的部分。
-
任何一个只接受一个参数,且在运行时传入的参数实现了
Serializable
接口的连接点 (在Spring AOP中只是方法执行)args(java.io.Serializable)
'args'在binding form中用的更多:- 请常见以下讨论通知的章节中关于如何使得方法参数可以在通知体内访问到的部分。
请注意在例子中给出的切入点不同于
execution(* *(java.io.Serializable))
: args只有在动态运行时候传入参数是可序列化的(Serializable)才匹配,而execution 在传入参数的签名声明的类型实现了Serializable
接口时候匹配。 -
有一个
@Transactional
注解的目标对象中的任意连接点(在Spring AOP中只是方法执行)@target(org.springframework.transaction.annotation.Transactional)
'@target' 也可以在binding form中使用:请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
-
任何一个目标对象声明的类型有一个
@Transactional
注解的连接点(在Spring AOP中只是方法执行)@within(org.springframework.transaction.annotation.Transactional)
'@within'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
-
任何一个执行的方法有一个
@Transactional
annotation的连接点(在Spring AOP中只是方法执行)@annotation(org.springframework.transaction.annotation.Transactional)
'@annotation' 也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。
-
任何一个接受一个参数,并且传入的参数在运行时的类型实现了
@Classified
annotation的连接点(在Spring AOP中只是方法执行)@args(com.xyz.security.Classified)
'@args'也可以在binding form中使用:- 请常见以下讨论通知的章节中关于如何使得annotation对象可以在通知体内访问到的部分。