Spring注解驱动AOP开发入门
1. AOP思想
AOP(Aspect Oriented Programming): 面向切面编程
通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。为OOP(面向对象编程)的延续
是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率
2. 实现原理
基于动态代理技术实现。
动态代理技术:
特点:字节码随用随创建,随用随加载
分类:基于接口的动态代理,基于子类的动态代理
作用:不修改源码的基础上对方法增强
1.基于接口的动态代理
提供者:JDK官方
使用要求:被代理类最少实现一个接口
涉及的类:Proxy
创建代理对象的方法:newProxyInstance
方法参数:
ClassLoader:类加载器,加载代理对象的字节码
Class[]:字节码数组,给代理对象提供方法
被代理类为普通类:被代理对象.getClass().getInterfaces()
被代理类为接口:new Class[]{被代理对象.class}
InvocationHanlder:要增强的方法。为一个接口,需提供实现类(通常为匿名内部类)
2.基于子类的动态代理
提供者:第三方cglib包,需先导入maven坐标
使用要求:被代理类不能为最终类,不能被final修饰
涉及的类:Enhancer
创建代理对象的方法:create
方法的参数:
Class:字节码。被代理对象的字节码。可创建子类及获取类加载器
Callback:增强的代码。通常写一个接口的实现类或匿名内部类
Callback中美誉任何方法,通常使用它的子接口MethodInterceptor
3. Spring中AOP的术语
Joinpoint(连接点):所谓连接点是指被拦截到的点。spring只支持方法类型的连接点
Pointcut(切入点):指我们要进行拦截的Joinpoint
Advice(通知/增强):拦截到Joinpoint要做的事,分为前置,后置,异常,最终,环绕通知
Introduction(引介):引介是一种特殊的通知,在不修改类代码前提下在运行期动态添加一些方法
Target(目标对象):代理的目标对象
Weaving(织入):把增强应用到目标对象来创建新的代理对象的过程
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
Aspect(切面):切入点与通知(引介)的结合
4. 入门案例
4.1 案例介绍
需求: 实现在执行service方法时输出执行日志
4.2 案例实现
4.2.1 业务层接口
public interface UserService {
void save(User user);
}
4.2.2 业务层实现类
@Service("userService")
public class UserServiceImpl implements UserService{
@Override
public void save(User user) {
System.out.println("保存了:"+user);
}
}
4.2.3 日志工具类
@Component
@Aspect
public class LogUtil {
@Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1(){}
@Before("pt1()")
public void beforeLog(){
System.out.println("执行切入点方法前记录日志");
}
@AfterReturning("pt1()")
public void afterReturningLog(){
System.out.println("正常执行切入点方法后记录日志");
}
@AfterThrowing("pt1()")
public void afterThrowingLog(){
System.out.println("执行切入点方法产生异常后记录日志");
}
@After("pt1()")
public void afterLog(){
System.out.println("无论切入点方法执行是否有异常都记录日志");
}
@Around("pt1()")
public Object arountPrintLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
System.out.println("执行切入点方法前记录日志");
Object[] args = pjp.getArgs();
rtValue = pjp.proceed(args);
System.out.println("正常执行切入点方法后记录日志");
}catch (Throwable t){
System.out.println("执行切入点方法产生异常后记录日志");
}finally {
System.out.println("无论切入点方法执行是否有异常都记录日志");
}
return rtValue;
}
}
4.2.4 配置类
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfiguration {
}
4.2.5 测试类
public class SpringAOPTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
UserService userService = ac.getBean("userService",UserService.class);
User user = new User();
user.setId("1");
user.setUsername("test");
user.setNickname("泰斯特");
userService.save(user);
}
}