Spring Aop

AOP 是什么?

面向切面编程(Aspect Oriented Programing)

应用场景

适用于具备横切逻辑的场合,如性能检测、访问控制、事务管理及日志记。编程

AOP

两种拦截方式

  • 基于注解
  • 基于方法

链接点 JoinPoint

Spring 近支持方法的链接点,能在方法调用前、方法调用后、方法抛出异常时及方法调用先后这些执行点织入加强bash

链接点是客观存在的方法ide

切点 Pointcut

指定在哪些类的哪些方法上织入横切逻辑
一个切点能够匹配多个链接点
对应链接点表达式性能

加强 Advice

加强是织入目标类链接点上的横切逻辑代码,包含定位链接点的方位信息ui

  • 前置加强:方法执行前加强 @Before("logPointCut()")
  • 后置加强:方法执行后加强 @After("logPointCut()")
  • 环绕加强:方法执行先后加强 @Around("logPointCut()")
  • 异常抛出加强:方法抛出异常后加强 @AfterThrowing()
  • 引介加强:在目标类添加新的方法和属性

切面 Aspect

切面由切点和加强组成。对应一个类this

织入

织入是将加强添加到目标类的具体链接点上的过程。
Spring采用动态代理织入,AspectJ采用编译器织入和类装载期织入。spa

实例

@Slf4j
@Aspect
@Component
public class LogAspect {
	
    ThreadLocal<Long> startTime = new ThreadLocal<>();
    
    @Pointcut("execution(public * com.pengtech.school.*.controller..*.*(..))")
    public void logPointCut(){
    }
    
    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
    	// 接收到请求,记录请求内容
    	ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    	HttpServletRequest request = attributes.getRequest();
    	startTime.set(System.currentTimeMillis());
    	log.info("########请求地址:" + request.getRequestURL());
    	log.info("########开始时间:" + LocalDateTime.now());
    	log.info("########请求方法:" + joinPoint.getSignature().getDeclaringTypeName() +
    		"." + joinPoint.getSignature().getName());
    	Object[] args = joinPoint.getArgs();
    	for (Object param : args) {
    		log.info("########方法参数:" + param);
    	}
    }
    
    @After("logPointCut()")
    public void doAfter() throws Throwable {
    	log.info("#######执行间隔:" + (System.currentTimeMillis() - startTime.get())
    			+ "ms");
    	log.info("#######完成时间:" + LocalDateTime.now());
    	
    }
}
复制代码

AOP 面向切面编程

概述

适合具备横切逻辑的应用场合,如性能监测、访问控制、事务管理和日志记录。

Spring AOP使用动态代理技术在运行期向目标类织入加强的代码。
复制代码

Spring AOP 两种代理机制

  • 基于JDK的动态代理
  • 基于CGLib的动态代理
JDK 动态代理
在运行期建立接口的代理实例
限制:只能为接口建立代理实例

// InvocationHandler 实现该接口定义横切逻辑,并经过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一块儿。
public class PerformanceHandler implements InvocationHandler {
    // 目标业务类
	private Object target;
	
	public PerformanceHandler(Object target){
		this.target = target;
	}
	
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
		// 横切代码
		PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
		// 反射调用目标类的目标方法
		Object object = method.invoke(target, args);
		// 横切代码
		PerformanceMonitor.end();
		return object;
	}
}
Proxy 利用InvocationHandler动态建立一个符合某一接口的实例,生成目标类的代理对象

// 使用JDK动态代理

    // 被代理的目标业务类
	ForumService target = new ForumServiceImpl();
	// 将目标业务类和横切代码编织到一块儿
	PerformanceHandler handler = new PerformanceHandler(target);
	// 建立代理实例
	ForumService proxy = (ForumService) Proxy.newProxyInstance(target
			.getClass().getClassLoader(),
			target.getClass().getInterfaces(), handler);
	// 调用代理方法		
	proxy.removeForum(10);
	proxy.removeTopic(1012);
复制代码

CGLib 动态代理

动态建立子类的方式生成代理对象
不能对final或private方法进行代理

//实现MethodInterceptor接口,并重写intercept方法
public class CglibProxy implements MethodInterceptor {
	private Enhancer enhancer = new Enhancer();

    //建立动态代理对象
	public Object getProxy(Class clazz) {
		enhancer.setSuperclass(clazz);
		enhancer.setCallback(this);
		return enhancer.create();
	}

    // 拦截全部目标类方法的调用
	@Override
	public Object intercept(Object obj, Method method, Object[] args,
	                        MethodProxy proxy) throws Throwable {
		PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());
		Object result=proxy.invokeSuper(obj, args);
		PerformanceMonitor.end();
		return result;
	}
	
	//动态生成子类的方式建立代理类
	CglibProxy cglibProxy = new CglibProxy();
	ForumService forumService = (ForumService)cglibProxy.getProxy(ForumServiceImpl.class);
	forumService.removeForum(10);
	forumService.removeTopic(1023);
}
复制代码
相关文章
相关标签/搜索