spring提供四种各具特色的AOP支持:
①基于代理的经典AOP(利用ProxyFactoryBean进行XML配置,这种做法spring2.0以前常用配置)
②Schema-based的AOP(利用<aop:config>)
③@ASpectJ注解驱动的AOP
④注入式AspectJ的AOP(其实与Spring并无多大的关系,这个就是使用AspectJ这个框架实现Aop编程)
下面我们对前三种类型分别进行介绍。
-
基于代理的经典AOP
这种方式是使用ProxyFactoryBean来创建的,下面对几个主要的类进行概要说明:
按方法名字匹配:org.springframework.aop.support.NameMatchMethodPointcut 成员变量:mappedNames匹配方法名集合
前置通知:org.springframework.aop.MethodBeforeAdvice
后置通知:org.springframework.aop.AfterReturningAdvice
环绕通知:org.aopalliance.intercept.MethodInterceptor (这个依赖于aopalliance-1.0.jar这个包)
异常通知:org.springframework.aop.ThrowsAdvice
ProxyFactoryBean使用时有以下几方面需要注意:
被代理的类没有实现任何接口,使用CGlib代理,否则使用JDK代理。
通过设置proxyTargetClass为true,可强制使用CGlib代理。
如果目标类实现一个或者多个接口,那么创建代理的类型将依赖ProxyFactoryBean的配置,XML文件中使用proxyInterfaces属性设置。
如果ProxyFactoryBean的proxyInterfaces属性设置了接口,那么这个将采用JDK代理,如果没有设置接口,但是目标类实现了一个或多个接口,那么ProxyFactoryBean会自动检测,并创建一个基于JDK的代理。
具体例子如下:
IStudentService :
public interface IStudentService {
public void save();
}
StudentServiceImpl :
public class StudentServiceImpl implements IStudentService {
@Override
public void save() {
System.out.println("添加成功.....");
}
}
StudentBeforeAdvice (前置通知):
public class StudentBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("StudentBeforeAdvice : " + method.getName() + target.getClass().getSimpleName());
}
}
StudentAfterAdvice (后置通知):
public class StudentAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnVal, Method method, Object[] args, Object target) throws Throwable {
System.out.println("StudentAfterAdvice :" + method.getName() +" "+target.getClass().getSimpleName() +" " + returnVal);
}
}
StudentMethodInterceptor (环绕通知):
public class StudentMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("StudentMethodInterceptor1 :" + invocation.getMethod().getName() +" "+invocation.getStaticPart().getClass().getSimpleName());
Object obj = invocation.proceed();
System.out.println("StudentMethodInterceptor2 " + obj);
return obj;
}
}
StudentThrowAdvice (异常通知):
/**
* 实现ThrowsAdvice,只是一个标记,需要我们定义afterThrowing方法
*/
public class StudentThrowAdvice implements ThrowsAdvice {
public void afterThrowing(Method method,Object[] args,Object target,Exception ex){
System.out.println("StudentThrowAdvice :" + method.getName()+" "+target.getClass().getSimpleName() );
}
}
测试方法:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-api.xml");
IStudentService studentServicet = (IStudentService) context.getBean("studentServiceImpl");
studentServicet.save();
}
}
配置文件有以下几种方式:
①针对每个类都配置通知
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentAfterAdvice" class="com.base.java.aop.api.StudentAfterAdvice"></bean>
<bean id="studentThrowAdvice" class="com.base.java.aop.api.StudentThrowAdvice"></bean>
<bean id="studentMethodInterceptor" class="com.base.java.aop.api.StudentMethodInterceptor"></bean>
<bean id="studentServiceImplTarget" class="com.base.java.aop.api.StudentServiceImpl"></bean>
<bean id="studentServiceImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--此处可以指定该类实现接口也可以不指定,不指定ProxyFactoryBean自动查找
<property name="proxyInterfaces">
<value>com.base.java.aop.api.IStudentService</value>
</property>-->
<property name="target">
<ref bean="studentServiceImplTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>studentBeforeAdvice</value>
<value>defaultAdvisor</value>
<value>studentAfterAdvice</value>
<value>studentMethodInterceptor</value>
<value>studentThrowAdvice</value>
</list>
</property>
</bean>
②利用DefaultPointcutAdvisor配置通知,但是这种方式只能配置一个pointcut和一种通知
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentAfterAdvice" class="com.base.java.aop.api.StudentAfterAdvice"></bean>
<bean id="studentThrowAdvice" class="com.base.java.aop.api.StudentThrowAdvice"></bean>
<bean id="studentMethodInterceptor" class="com.base.java.aop.api.StudentMethodInterceptor"></bean>
<bean id="studentServiceImplTarget" class="com.base.java.aop.api.StudentServiceImpl"></bean>
<bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>sa*</value>
</list>
</property>
</bean>
<bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="studentBeforeAdvice"/>
<property name="pointcut" ref="pointcutBean"/>
</bean>
<bean id="studentServiceImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="studentServiceImplTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>defaultAdvisor</value>
<value>studentAfterAdvice</value>
<value>studentMethodInterceptor</value>
<value>studentThrowAdvice</value>
</list>
</property>
</bean>
③使用匿名的内部Bean来隐藏目标和代理之间的区别
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentAfterAdvice" class="com.base.java.aop.api.StudentAfterAdvice"></bean>
<bean id="studentThrowAdvice" class="com.base.java.aop.api.StudentThrowAdvice"></bean>
<bean id="studentMethodInterceptor" class="com.base.java.aop.api.StudentMethodInterceptor"></bean>
<bean id="studentServiceImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="com.base.java.aop.api.StudentServiceImpl"></bean>
</property>
<property name="interceptorNames">
<list>
<value>studentBeforeAdvice</value>
<value>defaultAdvisor</value>
<value>studentAfterAdvice</value>
<value>studentMethodInterceptor</value>
<value>studentThrowAdvice</value>
</list>
</property>
</bean>
④简化Porxy定义
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentAfterAdvice" class="com.base.java.aop.api.StudentAfterAdvice"></bean>
<bean id="studentThrowAdvice" class="com.base.java.aop.api.StudentThrowAdvice"></bean>
<bean id="studentMethodInterceptor" class="com.base.java.aop.api.StudentMethodInterceptor"></bean>
<bean id="studentServiceImplTarget" class="com.base.java.aop.api.StudentServiceImpl"></bean>
<bean id="baseProxyBean" class="org.springframework.aop.framework.ProxyFactoryBean"
lazy-init="true" abstract="true"></bean>
<bean id="studentServiceImpl" parent="baseProxyBean">
<property name="target">
<bean class="com.base.java.aop.api.StudentServiceImpl"></bean>
</property>
<property name="proxyInterfaces">
<value>com.base.java.aop.api.IStudentService</value>
</property>
<property name="interceptorNames">
<list>
<value>studentBeforeAdvice</value>
<value>studentAfterAdvice</value>
<value>studentMethodInterceptor</value>
<value>studentThrowAdvice</value>
</list>
</property>
</bean>
⑤基于BeanNameAutoProxyCreator自动代理
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentAfterAdvice" class="com.base.java.aop.api.StudentAfterAdvice"></bean>
<bean id="studentThrowAdvice" class="com.base.java.aop.api.StudentThrowAdvice"></bean>
<bean id="studentMethodInterceptor" class="com.base.java.aop.api.StudentMethodInterceptor"></bean>
<bean id="studentServiceImpl" class="com.base.java.aop.api.StudentServiceImpl"></bean>
<!--配置自动代理-->
<!--配置基于BeanNameAutoProxyCreator类的自动代理-->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<!--配置作用于的bean,也就是筛选BeanName,以配置文件中<bean> id为准-->
<property name="beanNames" value="*Impl"></property>
<!--配置增强处理-->
<property name="interceptorNames">
<list>
<value>studentBeforeAdvice</value>
<value>studentAfterAdvice</value>
<value>studentMethodInterceptor</value>
<value>studentThrowAdvice</value>
</list>
</property>
</bean>
⑥基于DefaultAdvisorAutoProxyCreator自动代理
这个自动代理可以指定切面切入点和BeanNameAutoProxyCreator的区别是BeanNameAutoProxyCreator针对的是类。
<bean id="studentBeforeAdvice" class="com.base.java.aop.api.StudentBeforeAdvice"></bean>
<bean id="studentServiceImplTarget" class="com.base.java.aop.api.StudentServiceImpl"></bean>
<!--配置切面-->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern" value=".*save"></property><!--对切入点进行过滤-->
<property name="advice" ref="studentBeforeAdvice"></property>
</bean>
<!--基于切面信息来产生自动代理-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
-
Schema-based的AOP
①AOP配置元素说明:
AOP 配置元素 | 描述 |
aop : advisor | 定义 AOP 通知器 |
aop : after | 定义 AOP 后置通知(不管被通知方法是否执行成功) |
aop : after-returing | 定义 AOP after-returing 通知 |
aop : after-throwing | 定义 AOP after-throwing 通知 |
aop : around | 定义 AOP 环绕通知 |
aop : aspect | 定义切面 |
aop : aspectj-autoproxy | 启动 @AspectJ 注解驱动的切面 |
aop : before | 定义 AOP 前置通知 |
aop : config | 顶层的 AOP 配置元素,大多数 aop : * 元素必须包含在 元素内 |
aop : declare-parents | 为被通知的对象引入额外接口,并透明的实现 |
aop : pointcut | 定义切点 |
②Expression举例说明:
表达式 | 描述 |
execution(public * *(..)) | 任意公共方法的执行 |
execution(* set*(..)) | 任何一个以“set”开始的方法 |
execution(* com.xyz.service.AccountService.*(..)) | AccountService 接口的任意方法的执行 |
execution(* com.xyz.service.*.*(..)) | 定义在service包里的任意方法的执行 |
execution(* com.xyz.service..*.*(..)) | 定义在service包和所有子包里的任意类的任意方法 |
execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))") | 定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法 |
within(com.xys.*) | 包中的所有类的所有方法. |
within(com.xys.service.*Service) | 表示在 com.xys.service 包中所有以 Service 结尾的类的所有的连接点 |
bean(*Service) | 匹配以指定名字结尾的 Bean 中的所有方法 |
bean(*Service) && within(com.xys.service.*) | 匹配名字以 Service 结尾, 并且在包 com.xys.service 中的 bean |
this(com.test.spring.aop.pointcutexp.MyInterface) | 实现了MyInterface接口的所有类,如果MyInterface不是接口,限定MyInterface单个类 |
args |
|
...... | ...... |
target、this、within的区别:
target匹配目标对象的类型,即被代理对象的类型,例如A继承了B接口,则使用target("B"),target("A")均可以匹配到A
this匹配的是代理对象的类型,例如存在一个接口B,使用this("B"),如果某个类A的JDK代理对象类型为B,则A实现的接口B的方法会作为切点进行织入。
within比较严格,它是严格匹配被代理对象类型的,不会理会继承关系,例如A继承了接口B,则within("B")不会匹配到A,但是within("B+")可以匹配到A。
<aop:config>风格的配置大量的使用了Spring的自动代理机制。
③具体例子:
AspectBiz :
public class AspectBiz {
public void save(){
System.out.println("调用方法................");
}
public void init(String name,int times){
System.out.println("调用init....");
}
}
MoocAspect:
public class MoocAspect {
public void before(){
System.out.println("MoocAspect.before....");
}
public void afterReturning(){
System.out.println("MoocAspect.afterReturning.....");
}
public void afterThrowing(){
System.out.println("MoocAspect.afterThrowing...");
}
public void after(){
System.out.println("MoocAspect.after...");
}
/**
* 环绕通知第一个参数必须是ProceedingJoinPoint
* @param pre
* @throws Throwable
*/
public void around(ProceedingJoinPoint pre) throws Throwable {
System.out.println("MoocAspect.around1....");
pre.proceed();
System.out.println("MoocAspect.around2....");
}
public void aroundInit(ProceedingJoinPoint pre,String name,int times) throws Throwable {
System.out.println("MoocAspect.aroundInit : " + name + times);
System.out.println("MoocAspect.aroundInit1....");
pre.proceed();
System.out.println("MoocAspect.aroundInit2....");
}
}
测试方法:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-schema.xml");
AspectBiz aspectBiz = (AspectBiz)context.getBean("aspectBiz");
//aspectBiz.save();
aspectBiz.init("11",12);
}
}
配置文件:
<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/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="moocAspect" class="com.base.java.aop.schema.MoocAspect"></bean>
<bean id="aspectBiz" class="com.base.java.aop.schema.AspectBiz"></bean>
<aop:config>
<aop:aspect id="moocAspectAOP" ref="moocAspect">
<aop:pointcut expression="execution(* com.base.java.aop.schema.*Biz.*(..))" id="moocPiontcut"/>
<aop:before method="before" pointcut-ref="moocPiontcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="moocPiontcut"/>
<aop:after method="after" pointcut-ref="moocPiontcut"/>
<aop:around method="around" pointcut-ref="moocPiontcut"/>
<aop:around method="around" pointcut="execution(* com.base.java.aop.schema.AspectBiz.init(String,int))) and args(name, times)"/>
</aop:aspect>
</aop:config>
</beans>
④introduction引入增强的一个例子:
Fit :
public interface Fit {
void filter();
}
FitImpl :
public class FitImpl implements Fit {
@Override
public void filter() {
System.out.println("FitImpl filter");
}
}
测试方法:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-schema.xml");
//此处获取的是接口
Fit fit = (Fit)context.getBean("aspectBiz");
fit.filter();
}
}
配置文件:
<bean id="moocAspect" class="com.base.java.aop.schema.MoocAspect"></bean>
<bean id="aspectBiz" class="com.base.java.aop.schema.AspectBiz"></bean>
<aop:config>
<aop:aspect id="moocAspectAOP" ref="moocAspect">
<aop:declare-parents types-matching="com.base.java.aop.schema.*" implement-interface="com.base.java.aop.schema.Fit" default-impl="com.base.java.aop.schema.FitImpl"/>
</aop:aspect>
</aop:config>
</beans>
说明:
①引入增强是类级别的,所以不存在切点表达式。
②利用 <aop:declare-parents> 节点在 <aop:aspect> 内部声明
③types-matching 属性,要增强的目标类,这里需要全类名。
④implement-interface 属性:动态的增强类接口。
⑤default-impl 属性:动态增强类接口的实现类。
⑤Advisors
Adivisor是一种特殊的Aspect,Advisor代表spring中的Aspect
advisor只持有一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice
基于事务xml配置:
<tx:advice id="daoAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="delect*" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* dao.*.*(..))" id="daoMethod"/>
<aop:advisor advice-ref="daoAdvice" pointcut-ref="daoMethod"/>
</aop:config>
-
@ASpectJ注解驱动的AOP
@AspectJ是一种使用java注解来实现AOP,这种风格是在AspectJ5引入,并且spring也支持这种风格。
对@AspectJ支持可以使用XML或Java风格配置,不论哪种配置我们要引入aspectjweaver.jar,版本在1.6.8或者更高。
1)Java方式配置:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
2)XML方式配置:
<aop:aspectj-autoproxy/>
3)切入点表达式:
AspectJ 指示器 | 描述 |
arg () | 限制连接点的指定参数为指定类型的执行方法 |
@args () | 限制连接点匹配参数由指定注解标注的执行方法 |
execution () | 用于匹配连接点的执行方法 |
this () | 限制连接点匹配 AOP 代理的 Bean 引用为指定类型的类 |
target () | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型注解 |
within() | 限制连接点匹配指定类型 |
@within() | 限制连接点匹配指定注释所标注的类型(当使用 Spring AOP 时,方法定义在由指定的注解所标注的类里) |
@annotation | 限制匹配带有指定注释的连接点 |
4)常用切入点表达式:
①匹配方法签名
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(..))
// 匹配当前包中的指定类的所有方法
execution(* UserService.*(..))
// 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(..))
// 匹配指定包中的所有 public 方法, 并且返回值是 int 类型的方法
execution(public int com.xys.service.*(..))
// 匹配指定包中的所有 public 方法, 并且第一个参数是 String, 返回值是 int 类型的方法
execution(public int com.xys.service.*(String name, ..))
②匹配类型签名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*)
// 匹配指定包中的所有的方法, 包括子包
within(com.xys.service..*)
// 匹配当前包中的指定类中的方法
within(UserService)
// 匹配一个接口的所有实现类中的实现的方法
within(UserDao+)
③匹配 Bean 名字
// 匹配以指定名字结尾的 Bean 中的所有方法
bean(*Service)
④切点表达式组合
// 匹配以 Service 或 ServiceImpl 结尾的 bean
bean(*Service || *ServiceImpl)
// 匹配名字以 Service 结尾, 并且在包 com.xys.service 中的 bean
bean(*Service) && within(com.xys.service.*)
⑤匹配参数
// 匹配第二个参数为 name 的方法
@Before(value = "aspectMethod() && args(*, name, ..)")
public void doSomething(String name) {
}
5)@Aspect
仅使用@AspectJ注解,是不能够通过类路径检测发现的,所以需要配合使用@component注解或者使用XML配置切面Bean。类使用@AspectJ之后,这个类就排除在auto-proxying机制之外。
6)@Pointcut
一个 pointcut 的声明由两部分组成:
一个方法签名, 包括方法名和相关参数,返回值类型为void。
一个 pointcut 表达式, 用来指定哪些方法执行是我们感兴趣的(即因此可以织入 advice)。
7)具体例子
配置文件:
<?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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.base.java.aop.aspectj"/>
<aop:aspectj-autoproxy />
</beans>
MoocBiz:
@Service
public class MoocBiz {
@MoocMethod("this is a annotation")
public String save(String arg){
System.out.println("MoocBiz save:" + arg);
//throw new RuntimeException("save fail");
return "Save success";
}
}
MoocAscpet:
@Component
@Aspect
public class MoocAscpet {
@Pointcut("execution(* com.base.java.aop.aspectj.*Biz.*(..))")
public void pointcut(){
}
@Pointcut("execution(* com.base.java.aop.aspectj.*Biz.*(..)) && @annotation(moocMethod)")
public void pointcutAnnotation(MoocMethod moocMethod){
}
@Pointcut("within(com.base.java.aop.aspectj.*)")
public void bizPointcut(){
}
@Before("pointcut()")
//@Before("execution(* com.base.java.aop.aspectj.*Biz.*(..))")
public void before(){
System.out.println("Before......");
}
@Before("pointcut() && args(arg)")
public void beforeWithParam(String arg){
System.out.println("beforeWithParam : " + arg);
}
@Before("pointcut() && @annotation(moocMethod)")
public void beforeWithAnnotation(MoocMethod moocMethod){
System.out.println("beforeWithAnnotation " + moocMethod.value());
}
@Before("pointcutAnnotation(moocMethod)")
public void beforeWithAnnotation1(MoocMethod moocMethod){
System.out.println("beforeWithAnnotation1 " + moocMethod.value());
}
@AfterReturning(pointcut = "pointcut()",returning = "returnValue")
public void afterReturning(Object returnValue){
System.out.println("afterReturning : " + returnValue);
}
@AfterThrowing(pointcut = "pointcut()",throwing = "e")
public void afterThrowing(RuntimeException e){
System.out.println("afterThrowing : " + e.getMessage());
}
@After("pointcut()")
public void after(){
System.out.println("after.");
}
//方法第一个参数必须是ProceedingJoinPoint类型,返回值时Object
@Around("pointcut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("around1。。。");
Object obj = point.proceed();
System.out.println("around2...." + obj);
return obj;
}
}
MoocMethod:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MoocMethod {
String value() default "";
}
测试类:
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-aspectj.xml");
MoocBiz biz = (MoocBiz) context.getBean("moocBiz");
biz.save("this is test..");
}
}
8)切面实例化模型
在@Aspect使用perthis后,每个独立的service对象执行时都会创建一个切面实例,切面实例在方法第一次调用时创建,在service对象失效时同时失效。使用方式:@Aspect("perthis(com.java.businessService())")。
9)AOP基于泛型的应用
Base:
public interface Base<T> {
public void save(T t);
public void update(T t);
}
BaseImpl:
public class BaseImpl<T> implements Base<T> {
@Override
public void save(T t) {
System.out.println("BaseImpl-save()");
}
@Override
public void update(T t) {
System.out.println("BaseImpl-update()");
}
}
BaseAspect:
@Aspect
@Component
public class BaseAspect<T> {
@Before("execution(* com.base.java.aop.aspectj.BaseImpl.save(..)) && args(t))")
public void save(T t){
System.out.println("aspect - save(), " + t.getClass().getSimpleName());
}
@Before("execution(* com.base.java.aop.aspectj.BaseImpl.update(..)) && args(t))")
public void update(T t) {
System.out.println("aspect - update(), " + t.getClass().getSimpleName());
}
}
ObjectA :
public class ObjectA {
}
ObjectAService :
public interface ObjectAService extends Base<ObjectA> {
public void supportMethod(ObjectA a);
}
ObjectAServiceImpl :
@Service("obaService")
public class ObjectAServiceImpl extends BaseImpl<ObjectA> implements ObjectAService {
@Override
public void supportMethod(ObjectA a) {
System.out.println("supportMethod");
}
@Override
public void save(ObjectA a){
System.out.println("-------------------");
}
}
测试类:
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-aop-aspectj.xml");
ObjectAService biz = (ObjectAService) context.getBean("obaService");
biz.supportMethod(new ObjectA());
biz.save(new ObjectA());
biz.update(new ObjectA());
}
}
输出结果:
supportMethod
aspect - save(), ObjectA
-------------------
aspect - update(), ObjectA
BaseImpl-update()
注意:存在继承关系的类中,如果对父类做切面,其子类同时也会被切到。对类做切面使用的是CGLib代理,对接口对切面使用的是JDK代理。