目录
SpringAOP的一点理解
SpringAOP的基本术语
通过注解使用springAOP
springAOP的引入
其实springaop就是一个拦截器,springaop通过代理模式实现方法的拦截
1、切面:拦截器类,其中会定义切点以及通知
2、通知:切面当中的方法,包括:
3、引入:往代理对象中添加新的方法,但是新的方法不会被拦截
4、切点:即定义需要拦截的方法的特征,可以通过正则表达式匹配,也可以通过类的全限定名
5、连接点:需要拦截的方法
6、织入:生成代理对象并将切面内容嵌入流程中,将切面内容嵌入到流程中是什么意思呢?例如现在定义了前置通知,那么代理对象在调用被代理对象的方法之前就会调用前置通知
@Aspect:表明这个类是一个切面
@Before:前置通知
@After:后置通知
@AfterReturning:正常通知
@AfterThrowing:异常通知
@Pointcut:切点,切点匹配方法有如下几种方式:
下面举一个简单的例子,项目结构:
Roleinterface:
package com.springdemo3;
public interface Roleinterface {
void print();
}
Roleimplement:
package com.springdemo3;
public class Roleimplement implements Roleinterface{
//连接点
public void print() {
System.out.println("this is AOP");
}
}
AOP(切面):
package com.springdemo3;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
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;
@Aspect
public class AOP {
//切点
@Pointcut("target(com.springdemo3.Roleimplement)")
public void print() {};
//前置通知
@Before("print()")
public void beforeprint() {
System.out.println("这是前置方法");
}
//后置通知
@After("print()")
public void afterprint() {
System.out.println("这是后置方法");
}
//返回通知
@AfterReturning("print()")
public void afterreturning() {
System.out.println("正常返回");
}
//异常通知
@AfterThrowing("print()")
public void afterthrowing() {
System.out.println("异常防护");
}
}
configurations(配置类):
package com.springdemo3;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.Bean;
@Configuration
@EnableAspectJAutoProxy
public class configurations {
@Bean
public Roleimplement getRoleinplement() {
return new Roleimplement();
}
@Bean
public AOP getAOP() {
return new AOP();
}
}
App(启动类):
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
*/
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(configurations.class);
Roleinterface temp=(Roleinterface)ctx.getBean(Roleinterface.class);
temp.print();
}
}
关于springAOP相应的内容都已经标记出,接下来我们看看环绕通知,在切面中添加函数,函数参数ProceedingJoinPoint可以调用proceed方法,该方法会调用连接点,同时调用前置通知:
@Around(value = "print()")
public void aroundfunc(ProceedingJoinPoint func) {
System.out.println("执行环绕方法");
try {
func.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕方法执行完毕");
}
运行结果:
当切面中存在环绕通知时,在外部调用连接点方法,其实调用的是环绕通知,proceed方法允许环绕通知调用连接点方法,proceed方法将前置通知与连接点捆绑在一起,环绕通知就相当于连接点,根据环绕通知的执行结果,决定调用异常通知或是正常通知
我对springAOP引入的理解就是增强代理对象的功能,其实就是让代理对象继承某些接口(不能是类),内部应该是通过反射的方式调用接口实现类的方法,为什么只能引入接口的方法呢?这是java代理方式决定的,CGLIB代理已经继承被代理类了(java是单继承),JDK代理对象生成的时候只能传递接口
(JDK生成代理对象的方法为Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this),看不到与类继承有关的参数)
使用引入,只需要在上述项目的基础上更改一下:
Userinterface:
package com.springdemo3;
public interface Userinterface {
void print_sec();
}
Userimplement:
package com.springdemo3;
public class Userimplement implements Userinterface{
public void print_sec() {
System.out.println("这是引入");
}
}
在AOP(切面)中添加:
//value表示引入应该应用于哪些被代理对象的代理对象
//defaultImpl表示接口的默认实现类是谁,引入的实现类会被注册为通知(advice)
@DeclareParents(value="com.springdemo3.Roleinterface+",defaultImpl=Userimplement.class)
Userinterface userinterface;
添加断点查看代理对象:
可以注意到引入被注册为了advice
当有多个通知应用于同一个连接点时,通知的执行顺序是不确定的,可以在切面类中使用@Order(优先级)来指定执行顺序,此时spring会将多个通知组织成责任链的模式