AOP
作用:在程序运行期间,在不修改源码情况下对方法功能进行功能增强
优势:减少重复代码,解耦合,便于维护
常用动态代理两种方式:
JDK代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术
JDK代理方式代码书写
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
Target target = new Target();
Advice advice = new Advice();
// 返回值就是动态生成的代理对象
TargetInterface proxyInstance = (TargetInterface) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标对象类加载器
target.getClass().getInterfaces(), //目标对象相同的接口字节码对象组
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.preAdvice(); // 前置增强
method.invoke(target,args); // 执行目标方法
advice.postAdvice(); // 后置增强
return null;
}
}
);
// 调用代理对象的方法
proxyInstance.save();
}
}
cglib代理代码书写
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class ProxyTest {
public static void main(String[] args) {
// 目标对象
Target target = new Target();
// 增强对象
Advice advice = new Advice();
// 返回值就是动态生成的代理对象, 基于cglib
// 1、创建增强器
Enhancer enhancer = new Enhancer();
// 2、设置父类
enhancer.setSuperclass(Target.class);
// 3、设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
advice.preAdvice(); // 前置增强
Object invoke = method.invoke(target, objects);// 传入对象和相应参数
advice.postAdvice(); // 后置增强
return invoke;
}
});
// 4、创建代理对象
Target targetProxy = (Target) enhancer.create();
targetProxy.save();
}
}
SpringAOP实现
Spring框架监控切入点方法的执行,一旦监控到切入方法的执行使,用代理机制动态创建目标对象的代理对象。根据通知类别在代理对象的对应位置,将通知对应的功能织入,完成完整代码逻辑的运行。
需要明确事项:
1、谁是切点
2、谁是通知(增强)
3、将切点和通知进行织入配置
切点表达式:
- 访问修饰符可省略
- 返回值类型、包名、方法名、可以使用*替代任意
- 报名中间一个.表示当前包下的类,两个…代表当前包下及其子包下的类
- 参数列表可以使用…表示任意个数和任意参数类型
- 可通过配置进行切点表达式抽取
execution(public void com.AOP.Target.save()) // 表示sava方法
execution(void com.AOP.Targer.*(..)) // Target类下的所有方法
execution(* com.AOP.*.*(..)) // AOP包和其下面的包下的所有方法
几种增强方式:
前置增强:before
后置增强:after-returning
环绕增强:around(需要传入参数 ProceedingJoinPoint proceedingJoinPoint)在方法中执行Object proceed = proceedingJoinPoint.proceed(); 返回proceed
抛出异常增强:after-throwing
最终增强:after
配置文件:
<aop:config>
<aop:aspect ref="myAspect">
<!-- 切点表达式抽取-->
<aop:pointcut id="myPointcut" expression="execution(* com.AOP..*(..))"/>
<!-- 前置增强-->
<aop:before method="before" pointcut-ref="myPointcut"/>
<!-- 后置增强-->
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<!-- 环绕增强-->
<aop:around method="around" pointcut-ref="myPointcut"/>
<!-- 抛出异常增强-->
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<!-- 最终增强,无论是否发生异常都会最终执行-->
<aop:after method="after" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
增强方法:
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void before() {
System.out.println("前置增强.......");
}
public void afterReturning() {
System.out.println("后置增强.......");
}
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("前置环绕增强.......");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("后置环绕增强.......");
return proceed;
}
public void afterThrowing() {
System.out.println("异常抛出增强.......");
}
public void after() {
System.out.println("最终增强.......");
}
}
注解方式:
开发步骤:
- 使用@Aspect标注切面类
- 使用@通知注解标注通知方法
- 在配置文件中配置AOP自动代理aop:aspectj-autoproxy
- 可使用@Pointcut抽取切点表达式
切面类:
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component("myAspect")
public class MyAspect {
@Pointcut("execution(* com.AnnoAOP..*(..))")
public void myPointcut(){}
@Before("myPointcut()")
public void before() {
System.out.println("前置增强.......");
}
@AfterReturning("MyAspect.myPointcut()")
public void afterReturning() {
System.out.println("后置增强.......");
}
@Around("execution(* com.AnnoAOP..*(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("前置环绕增强.......");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("后置环绕增强.......");
return proceed;
}
@AfterThrowing("execution(* com.AnnoAOP..*(..))")
public void afterThrowing() {
System.out.println("异常抛出增强.......");
}
@After("execution(* com.AnnoAOP..*(..))")
public void after() {
System.out.println("最终增强.......");
}
}