本文共 5348 字,大约阅读时间需要 17 分钟。
AOP(Aspect-Oriented Programming,面向切面编程)是一种软件开发方法,旨在通过横切关注点(Aspect)来提升代码的可维护性和复用性。与传统的面向对象编程相比,AOP允许开发者关注业务逻辑之外的其他常见任务,如日志记录、权限控制、事务管理等。
在现实编程中,许多系统功能的实现都会重复出现类似的代码逻辑。例如,鉴权模块、监控模块、日志记录模块等,这些功能在业务逻辑中难以通过纵向抽象来实现。AOP通过横向抽取机制,将这些分散的代码逻辑集中到独立的模块中,实现了“单一职责”的思想。
程序执行的某个特定位置,例如类初始化前后、函数调用前后、函数抛异常后等。连接点具有边界性质,能够明确区分代码的执行边界。
切点是用于定位特定连接点的规则。通过点剪切规则,可以为目标类中的特定连接点添加增强逻辑,而不需要为每个类或函数添加Advice。
增强是指在特定的连接点上插入额外的逻辑。增强可以是前置逻辑、后置逻辑或环绕逻辑。
目标对象是指被织入增强逻辑的对象。通过动态代理或字节码增强技术,将增强逻辑织入目标类。
引介是一种特殊的增强,用于为类或方法添加新的属性和方法。例如,可以通过引介为目标类中添加一些辅助方法。
织入是指将增强逻辑添加到目标类的连接点上的过程。通过动态代理或字节码技术,将增强逻辑与目标类的业务逻辑编织在一起。
在AOP中,目标类被织入增强后会生成一个新的代理类。代理类结合了原类和增强逻辑,通过动态代理技术实现对目标类方法的拦截和调试。
切面由切点和增强组成,表示系统中的一种横切关注点。Spring AOP负责将切面中的增强逻辑织入指定的连接点中。
静态代理是在编译时生成的代理类,通过继承或组合的方式实现对目标对象的代理。静态代理的优点是性能较高,但缺点是实现复杂度较高,且只能针对接口实现。
代理模式通过引入一个代理对象,间接地访问目标对象,实现对目标对象功能的扩展或增强。以下是一个简单的静态代理示例:
public interface Subject { void request();}public class RealSubject implements Subject { public void request() { // 业务逻辑 }}public class Proxy implements Subject { private Subject subject; public Proxy(Subject subject) { this.subject = subject; } public void request() { // 预处理逻辑 this.subject.request(); // 后处理逻辑 }} 动态代理是在运行时动态生成的代理类,适用于没有接口定义或需要频繁创建代理对象的情况。动态代理分为JDK动态代理和CGLIB动态代理。
JDK动态代理基于反射机制,通过动态生成代理类来实现目标类的方法拦截。以下是一个简单的JDK动态代理示例:
public class Monitor { public static void begin() { System.out.println("开始"); } public static void end() { System.out.println("结束"); }}public interface CouponService { void getCoupon();}public class CouponServiceImpl implements CouponService { public void getCoupon() { Monitor.begin(); try { System.out.println("业务代码"); } catch (Exception e) { throw new RuntimeException(e); } Monitor.end(); }}public class PerformanceHandler implements InvocationHandler { private Object target; public PerformanceHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Monitor.begin(); Object result = method.invoke(target, args); Monitor.end(); return result; }}public class Client { public static void main(String[] args) { CouponService target = new CouponServiceImpl(); PerformanceHandler performanceHandler = new PerformanceHandler(target); CouponService proxy = (CouponService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), performanceHandler ); proxy.getCoupon(); }} CGLIB动态代理通过字节码技术为目标类生成子类,从而实现方法拦截和增强。以下是一个简单的CGLIB动态代理示例:
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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("前置逻辑"); Object result = methodProxy.invokeSuper(o, objects); System.out.println("后置逻辑"); return result; }}public class Client { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); CouponServiceImpl service = (CouponServiceImpl) proxy.getProxy(CouponServiceImpl.class); service.getCoupon(); }} AspectJ是一种基于Java注解的AOP框架,能够在编译阶段将切面逻辑织入目标类中。以下是AspectJ的基本知识:
Java Configuration方式配置:
@Configuration@EnableAspectJAutoProxypublic class AOPConfig {} XML方式配置:
@Component@Aspectpublic class ControllerIntercept { @Pointcut("execution(public * com.ljw.controller.DiscernController.discern(..))") public void discernWeb() {}} @Pointcut("execution(public * com.ljw.discern_spider.controller.DiscernController.discern(..))")public void discernWeb() {} @Around("discernWeb()")public Object around(ProceedingJoinPoint joinPoint) { long start = System.currentTimeMillis(); try { before(joinPoint); return joinPoint.proceed(joinPoint.getArgs()); } catch (Throwable t) { return Result.createFalseRet().withErrMsg("around exception"); }} AOP是面向切面编程的一种技术,通过横切关注点实现对系统功能的统一管理。
转载地址:http://qgtkz.baihongyu.com/