什么是AOP?
通过预编译方式 和 运行期间动态代理 实现程度功能统一的维护技术
什么是动态代理模式?
不修改源码的情况下,对目标方法进行相应的增强,降低程序之间的耦合性
AOP 是 OOP(面向对象编程)的延续
AOP 优势
日志控制 解耦合
AOP 动态代理技术
- JDK代理 基于接口动态代理
- Cglib代理从 基于父类的动态代理
先说一下 Spring框架已经继承了,不用我们手动去写 动态代理的实现方式,但是我们也要了解一下
JDK动态代理实现方式
由于 JDK 动态代理 是基于JDK 不需要额外引入包
代码语言:javascript复制import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author : zanglikun
* @date : 2021/3/19 15:28
* @Version: 1.0
* @Desc : 费劲,没啥好说的
*/
public class ProxtTest {
public static void main(String[] args) {
// 目标对象
final Target target = new Target();
// 增强对象(自己写的)
Advice advice = new Advice();
/**
* JDK 动态代理方法 newProxyInstance 参数说明
* 参数1 目标的类加载器
* 参数2 目标的接口字节码
* 参数3 new InvocationHandler() 并重写党法
* 返回值类型 接口,所以 利用接口多态,进行接收
*/
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
advice.before();
method.invoke(target,args);
// 后置增强
advice.after();
return null;
}
});
proxy.save();
}
}
jdk下载
Cglib 动态代理
Cglib是 第三方lib包,但是 被Spring 已经引用了,仅需要按章Spring的依赖即可!!!
代码语言:javascript复制 <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
代码语言:javascript复制import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author : zanglikun
* @date : 2021/3/19 15:28
* @Version: 1.0
* @Desc : 费劲,没啥好说的
*/
public class ProxtTest {
public static void main(String[] args) {
// 目标对象
final Target target = new Target();
// 增强对象(自己写的)
Advice advice = new Advice();
// 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.before();
method.invoke(target,args);
advice.after();
return null;
}
});
// 4、创建代理对象
Target proxy = (Target) enhancer.create();
proxy.save();
}
}
cglib下载
AOP相关概念
Target 目标对象:代理的目标对象
Proxy 代理:一个类被AOP 织入增强后,就产生一个结果代理类
Joinpoint 连接点:可以被增强的方法
Poincut 切入点:对joinpoint 进行拦截
Advice 通知/增强:拦截到Joinpoint 之后做的事情
Aspect 切面:切入点和通知的结合 切点 通知
Weaving 织入:将切点 通知 创建的过程
AOP 开发 明确的事项
- 编写常规的业务逻辑 (目标类、目标方法)
- 编写切面类(通知)
- 在配置文件,配置织入关系,
AOP 底层使用的是目标有无接口 分别使用 jdk 和 cglib 的代理方式
AOP 基于 XML 快速入门
- 导入AOP相关坐标
- 创建目标接口 和 目标类
- 创建切面类
- 将目标类 和 切面类的对象创建权 交由Spring管理
- 在配置文件中 配置 织入关系
- 测试
导坐标
代码语言:javascript复制 <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
编写配置文件 ApplicaitonContext.xml
代码语言:javascript复制<?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: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="target" class="com.zanglikun.aop.Target"></bean>
<!-- 切面对象 -->
<bean id="myAspect" class="com.zanglikun.aop.MyAspect"></bean>
<!-- 配置织入 :告诉Spring 那些方法 进行那些增强(前置、后置)-->
<aop:config>
<!-- 声明切面 将普通的bean 变位 切面了-->
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut="execution(public void com.zanglikun.aop.Target.save())"></aop:before>
<aop:after method="after" pointcut="execution(public void com.zanglikun.aop.Target.save())"></aop:after>
</aop:aspect>
</aop:config>
</beans>
代码简图
这里 缺少一个 切点表达式的引用
切点表达式
AOP 通知种类
前置通知 :方法执行之前
后置通知:方法执行之后
环绕通知:方法执行前后 都执行
异常抛出通知:当目标方法抛异常才执行
最终通知:无论怎样,最终通知都要执行
注解AOP 开发
- 创建目标接口 目标类
- 创建切面类
- 将目标类 与 切面类 交由Spring进行管理
@Component
- 在切面类中使用 注解 配置织入关系
@Aespact 声明当前是一个切面类
在方法加注解
@Before(value = “切点表达式”)
- 在配置文件开启组件扫描 和 AOP自动代理
<context:component-scan base-package="com.zanglikun"/>
<aop:aspec-autoproxy/>
- 测试
@ContextConfiguration(“classpath:applicationContext.xml”)
注解开发时,AOP 切点表达式抽取
使用
@Pointcuy(切点表达式) 用来定义切点表达式 将来其他可直接引用
特殊说明: 解决问题的光鲜,藏着磕Bug的痛苦。 万物皆入轮回,谁也躲不掉! 以上文章,均是我实际操作,写出来的笔记资料,不会出现全文盗用别人文章!烦请各位,请勿直接盗用!