Spring Stu AOP
1. AOP
1.1 AOP介绍:实现原理,术语
面向切面编程—介绍
原理:
aop底层将采用代理机制进行实现。
接口+实现类:Spring擦爱用jdk的动态代理
实现类:spring采用cglib字节码增强
术语:
1.Taget: -----目标类:需要被代理的类 例如:userService
2. Joinpoint----链接点:所谓链接点是指那些可能被拦截到的方法。例如:目标类的方法
3.PointCut------切入点:已经被增强的链接点。例如:addUser();
4.advice------通知/增强:增强的代码,例如after,before();
5.Weaving----织入:是指把增强的advice应用到目标类对象target创建代理对象proxy的过程。
6.proxy 代理
7.Aspect—切面:切入点pointcut和通知advice的结合
一个pointcut和advice就能组成一个面
1.2 手动方式实现
1.2.1 JDK动态代理
Jdk动态代理 对“装饰者”设计模式的简化。前提:必须有接口
- 目标类:接口+实现类
- 切面类:用于存通知MyAspect
- 工厂类:工厂生成代理
- 测试
public class MyBeanFactory {
public static UserService craetService() {
//1目标类
UserService userService=new UserServiceImpl();
//2切面类
MyAspect myAspect =new MyAspect();
/*
* 3代理类
*
* 参数1:类加载器,动态代理类运行时创建,任何类都需要类加载器将其加载到内存
* 一般当前类.class.getClassLoader
* 参数2:代理类需要实现的所有接口
* 方案1:目标类.getClass().getInterfaces()
* 方案2:new Class[]{UserService.class}
* 参数3:处理类,接口。匿名内部类
* invoke方法:代理类的每一个方法执行时,都去调用invoke
* 参数3.1:Object arg0:代理对象
* 参数3.2:Method arg1:代理当前执行方法的描述对像(反射)
* 执行方法名:method.getName()
* 执行方法:method.invoke(对象,实际参数)
* 参数3.3:Object[] arg2:方法实际参数
*
*/
UserService proxyService=(UserService)Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
userService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
// 结合目标类和切面类
//前执行
myAspect.before();
//执行目标类的方法
Object obj=arg1.invoke(userService, arg2);
//后执行
myAspect.after();
return obj;
}
});
return proxyService;
}
}
1.2.2 CGLIB字节码增强
没有接口
采用字节码增强框架,运行的时候创建目标类的子类,从而对目标流泪进行增强。
导入jar包:
Spring-core…jar 内的asm和cglib
public class MyBeanFactory {
public static UserServiceImpl craetService() {
//1目标类
UserServiceImpl userService=new UserServiceImpl();
//2切面类
MyAspect myAspect =new MyAspect();
//3代理类
//核心类
Enhancer enhancer=new Enhancer();
//确定父类
enhancer.setSuperclass(userService.getClass());
//设置回调函数,MethodInterceptor接口
/*intercept和JDK中的invoke()等价
* 参数4方法的代理
*/
enhancer.setCallback(new org.springframework.cglib.proxy.MethodInterceptor() {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
//前方法
myAspect.before();
//执行目标类
Object obj=arg1.invoke(userService, arg2);
//后方法
myAspect.after();
return obj;
}
});
//3.4创建代理
UserServiceImpl proxService=(UserServiceImpl)enhancer.create();
return proxService;
}
}
1.2.3 Cglib和jdk动态代理的区别
参考:https://blog.csdn.net/XiYoumengshen/article/details/87909861
1.3 Spring编写代理:半自动
导入jar包:
核心4+1
AOP:A OP联盟、spring-aop
如:
aopalliance.jar—AOP联盟
下载地址:https://mvnrepository.com/artifact/org.aspectj/aspectjrt/1.8.10
aspectjweaver.jar
spring-aop-3.2.13.RELEASE.jar
1.4 Spring Aop编程:全自动【重要】
从spring容器获得目标类,如果配置aop,spring自动生成代理
要确定目标类,aspect切入点表达式------导入jar包
配置bean时需导入命名空间:
xmlns:aop=http://www.springframework.org/schema/aop
bean配置
<bean id="userServiceId" class="com.spring02.a_proxy.c_spring_aop.UserServiceImpl"></bean>
<!-- 2创建切面类 (通知) -->
<bean id="myAspectId" class="com.spring02.a_proxy.c_spring_aop.MyAspect"></bean>
<!-- 3 aop编程
1.导入命名空间
2.使用<aop:config>进行配置
<aop:pointcut >切入点,从目标对象获得具体方法
<aop:advisor> 特殊的切面,只有1个通知和一个切入点
advice-ref:通知的引用
pointcut-ref:切入点的引用
3.切入点表达式
execution(*com.spring02.a_proxy.c_spring_aop.UserServiceImpl.*(..)
execution(*com.spring02.a_proxy.c_spring_aop.*.*(..)
选择方法 返回值任意 包 类名任意 方法名任意 参数任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.spring02.a_proxy.c_spring_aop.*.*(..))" id="mypointCut"/>
<aop:advisor advice-ref="myAspectId" pointcut-ref="mypointCut"/>
</aop:config>
2. AspectJ
主要用途:自定义开发
2.1切入点表达式【掌握】
1.execution()用于描述方法
语法:execution(修饰符 返回值 包.类.方法(参数)throws异常)
修饰符:Public共有方法
* 任意
返回值:(不能省略)Void String *
2.2AspectJ通知类型
导入jar包4个:aop联盟,spring aop,aspect规范,spring aspect规范
2.3基于xml
1:目标类:接口和实现类
2:切面类:采用aspectj通知名称任意
3:aop编程:通知应用到目标类
2.4基于注解
包:com.spring02.d_aspectj_anno
2.4.1:Spring配置:
aop:aspectj-autoproxy</aop:aspectj-autoproxy> <context:component-scan base-package=“com.spring02.d_aspectj_anno”></context:component-scan>
2.4.2:aop注解总结
@Aspect 声明切面,修饰切面类,获得通知。
通知:
@Before @AfterReturning @Around
@AfterThrowing @After
//声明公共的切入点
@Pointcut(“execution(* com.spring02.d_aspectj_anno.UserServiceImpl.*(…))”)
public void myPointCut() {
}
//使用声明公共的切入点
在通知里:value=“myPointCut()”
参考:
Cglib和jdk动态代理的区别: https://blog.csdn.net/XiYoumengshen/article/details/87909861