AOP( 面向切面编程 )是一种思想,它的目的就是在不修改源代码的基础上,对原有功能进行增强。
SpringAOP是对AOP思想的一种实现,Spring底层同时支持jdk和cglib动态代理。
Spring会根据被代理的类是否有接口自动选择代理方式:
-
如果有接口,就采用jdk动态代理
-
如果没接口,就采用cglib的方式
jdk动态代理
// 代理工厂实现(AOP)
public class JDKProxyFactory {
// 获得代理对象的方法
public static Object getProxy(final Class clazz){
Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Logger logger = new Logger();
Object obj = null;
try {
// 前置增强
logger.m1();
// 告诉虚拟机要调用method方法
obj = method.invoke(clazz.newInstance(), args);
// 后置增强
logger.m2();
} catch (Exception e) {
e.printStackTrace();
logger.m3();
}
return obj; // 真实方法的返回值
}
});
return proxy; // 返回代理对象
}
}
cglib动态代理
public class CglibProxyFactory {
public static Object getProxy(final Class clazz){
// 创建一个代理工具类
Enhancer enhancer = new Enhancer();
// 根据父类创建子类对象
enhancer.setSuperclass(clazz);
// 调用代理对象的方法
enhancer.setCallback(new InvocationHandler() {
@Override
/**
* 参数1:代理对象本身的引用(一般不用)
* 参数2:代理对象调的方法
* 参数3:代理对象调的方法的参数
*/
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
Object invoke = null;
Logger logger = new Logger();
try {
// 前置增强
logger.m1();
// 告诉虚拟机要调用method方法
invoke = method.invoke(clazz.newInstance(), objects);
// 后置增强
logger.m2();
} catch (IllegalAccessException e) {
e.printStackTrace();
logger.m3();
}
return invoke; // 返回方法执行的返回值
}
});
// 生成代理对象并返回
Object proxy = enhancer.create();
return proxy;
}
}
实现步骤
导入依赖
<!--切点表达式解析坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
写增强类
@Component
@Aspect // 切面注解
public class Logger {
// 切点方式一 execution(返回值类型 方法路径) * 代表一个或多个位置 .. 代表0个或多个位置
// @Pointcut("execution(java.util.List com.itheima.service.impl.*.*(..))")
// 切点方式二 @annotation(自定义注解全限定类名)
@Pointcut("@annotation(com.itheima.annotation.LogAnno)")
public void pt(){}
// 四大通知
// 前置通知(before):增强方法在切点运行之前执行
// 返回后通知(after-returning):增强方法在某切点正常完成后执行的通知,不包括抛出异常的情况
// 异常后通知(after-throwing):增强方法在某切点抛出异常退出时执行的通知
// 后置通知(after):增强方法在某切点退出的时候执行的通知(不论是正常返回还是异常退出)
try{
前置通知(before)
//切点执行位置
返回后通知(after-returning)
}catch(Execption e){
异常后通知(after-throwing)
}finally{
后置通知(after)
}
// @Before("pt()")
// public void m1() {
// System.out.println("方法执行之前,执行了" + LocalDateTime.now());
// }
//
// @After("pt()")
// public void m2() {
// System.out.println("方法运行结束,执行了" + LocalDateTime.now());
// }
//
// @AfterReturning("pt()")
// public void m4() {
// System.out.println("方法返回结果后,执行了" + LocalDateTime.now());
// }
//
// @AfterThrowing("pt()")
// public void m3() {
// System.out.println("方法出现异常,执行了" + LocalDateTime.now());
// }
@Around("pt()")
public Object m5(ProceedingJoinPoint pjp){
Object object = null;
try {
System.out.println("方法执行前,执行了");
object = pjp.proceed();
System.out.println("方法执行后,执行了(return后)");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("方法异常了,执行了");
} finally {
System.out.println("方法运行到最后完全结束了,执行了");
return object;
}
}
}
配置类注解
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy // 激活切面自动代理
public class SpringConfig {
}