AOP介绍,AOP的一些术语,AspectJ概念,SpringAOP,动态代理
核心高级
AOP介绍
- AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构。
- AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
作用:AOP采取横向抽取机制,补充了传统纵向继承体系(OOP)无法解决的重复性代码优化(性能监视、事务管理、安全检查、缓存),将业务逻辑和系统处理的代码(关闭连接、事务管理、操作日志记录)解耦。
AOP的一些术语
- Pointcut 切入点 具体要增强的Joinpoint 方法
Advice 通知 对应增强的内容类,分为前置通知,后置通知,异常通知,最终通知,环绕
通知(切面要完成的功能)
Aspect 切面 切入点+通知,自己来编写和配置的
Proxy(代理)
Weaving(织入) 把增强应用到目标对象来创建新的代理对象的过程
AspectJ
AOP的一种早期实现,比较完善,实现的功能多。
有自己的编译器。
与JAVA无缝衔接。
静态织入
SpringAOP
动态代理实现,使用了JDK动态代理和CGlib动态代理实现
两种动态实现原理
类加载时动态生成一个类给目标类添加功能。
jdk动态代理
目标类必须实现一个接口
通过反射实现
比CGlib用的资源少
Spring先用jdk动态代理,目标类没有实现接口时使用CGlib代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| /** * 使用JDK的方式生成代理对象 */ public class MyProxyUtils { public static UserService getProxy(final UserService service) { // 使用Proxy类生成代理对象 UserService proxy = (UserService)Proxy.newProxyInstance(service.getClass(). getClassLoader(),service.getClass().getInterfaces(),new InvocationHandler() { // 代理对象方法一执行,invoke方法就会执行一次 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("save".equals(method.getName())){ System.out.println("记录日志..."); } // 让service类的save或者update方法正常的执行下去 return method.invoke(service, args); } }); // 返回代理对象 return proxy; } }
|
CGlib动态代理
通过继承目标类实现
目标类不能被 final 或static 修饰
单例时使用较好,因为创建一次消耗的资源较多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public static UserService getProxy(){ // 创建CGLIB核心的类 Enhancer enhancer = new Enhancer(); // 设置父类 目标类 enhancer.setSuperclass(UserServiceImpl.class); // 设置回调函数 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { if("save".equals(method.getName())){ // 记录日志 System.out.println("记录日志了..."); } return methodProxy.invokeSuper(obj, args); } }); // 生成代理对象 UserService proxy = (UserService) enhancer.create(); return proxy; }
|
基于AspectJ的aop使用
Spring+AspectJ整合
添加依赖
1 2 3 4 5 6 7 8 9 10 11
| <!-- 基于AspectJ的aop依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.0.7.RELEASE</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency>
|
目标类和方法
1 2
| UserService接口 UserServiceImpl实现类
|
xml实现
实现步骤
编写通知类
1 2 3 4 5
| public class MyAdvice{ public void log(){ System.out.println("记录日志"); } }
|
配置通知,交给IoC容器
1
| <bean name = "myAdvice" class = "com.xiaoruiit.advice.Myadvice"></bean>
|
配置切面
1 2 3 4 5 6 7 8 9 10 11
| <aop:config> <aop:aspect ref="myAdvice"> <!-- 对哪些切入点进行功能增强由pointcut属性指定 --> <!-- 增强哪些功能由method属性指定,它指定的方法是advice类中的方法 --> <!-- 什么时候织入?通过aop:before等标签来指定 --> <aop:before method="before" pointcut="execution(* *..*.*ServiceImpl.*(..))" /> <aop:after method="after" pointcut="execution(* *..*.*ServiceImpl.*(..))" /> </aop:aspect> </aop:config>
|
切入点表达式
1
| execution([修饰符] 返回值类型 包名.类名.方法名(参数))
|
通知类型
通知类型(五种):前置通知、后置通知、最终通知、环绕通知、异常抛出通知。
XML结合注解实现
实现步骤
1.编写切面类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @Component("myAspect") @Aspect public class MyAspect { private static final String pcut="execution(* *..*.*ServiceImpl.*(..))"; @Before(value="MyAspect.fn()") public void before() { System.out.println("这是注解方式的前置通知"); } @AfterReturning(pcut) public void after() { System.out.println("这是注解方式的后置通知"); } @Pointcut("execution(* *..*.*ServiceImpl.*(..))") public void fn() {} }
|
开启AOP自动代理
1 2
| <!-- 开启aspectj的自动代理,用于AOP的注解方式 --> <aop:aspectj-autoproxy/>
|
注解实现
取代开启Aspect自动代理xml文件
1 2 3 4
| @Configuration @ComponentScan(basePackages="com.xiaoruiit") @EnableAspectJAutoProxy public class SpringConfiguration { }
|