适用于具备横切逻辑的场合,如性能检测、访问控制、事务管理及日志记。编程
Spring 近支持方法的链接点,能在方法调用前、方法调用后、方法抛出异常时及方法调用先后这些执行点织入加强bash
链接点是客观存在的方法ide
指定在哪些类的哪些方法上织入横切逻辑
一个切点能够匹配多个链接点
对应链接点表达式性能
加强是织入目标类链接点上的横切逻辑代码,包含定位链接点的方位信息ui
切面由切点和加强组成。对应一个类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());
}
}
复制代码
适合具备横切逻辑的应用场合,如性能监测、访问控制、事务管理和日志记录。
Spring AOP使用动态代理技术在运行期向目标类织入加强的代码。
复制代码
在运行期建立接口的代理实例
限制:只能为接口建立代理实例
// 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);
复制代码
动态建立子类的方式生成代理对象
不能对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);
}
复制代码