前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring繁华的AOP王国---第一讲

Spring繁华的AOP王国---第一讲

作者头像
大忽悠爱学习
发布2022-05-10 16:05:05
2160
发布2022-05-10 16:05:05
举报
文章被收录于专栏:c++与qt学习

Spring繁华的AOP王国---第一讲


为什么需要AOP

在这里插入图片描述
在这里插入图片描述

我相信上面这张图已经可以很好的说明AOP的作用了,为什么需要AOP?

如果不通过aop,那么类似于上面这些功能,就需要耦合到代码中去,如果使用了aop,那么我们在业务代码中是看不到上面这些功能的实现语句的,这样就进行了解耦,并且仿佛这些功能是自动被横切到业务逻辑中去的一样,非常神奇。


AOP国家的公民

JoinPoint

在这里插入图片描述
在这里插入图片描述

OOP:面向对象编程 AOP:面向切面编程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JoinPoint总结就是横切逻辑的织入点,这里织入点可以是构造方法,普通方法,字段,类初始化。但是并不是每个AOP具体的实现都支持上面这些织入点,大多都支持部分。


PointCut

在这里插入图片描述
在这里插入图片描述

PointCut规定哪些织入点需要进行横切操作,然后这些织入点将被进行横切逻辑织入

PonitCut指定的这一组切入点就是一组JoinPoint


PointCut表达式

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

最后一点相信大家只要使用过spring aop aspectj实现的小伙伴都深有体会,即通过aspectj的表达式指定一个需要横切的范围,符合这些条件的方法都将被进行横切逻辑的织入


pointcut运算

在这里插入图片描述
在这里插入图片描述

不知道各位在使用spring aop的过程中是否使用过pointcut的运算功能,就是其实求并集或者交集,即扩大或者缩小范围


Advice

在这里插入图片描述
在这里插入图片描述

Advice就是具体要织入进去的横切逻辑,被织入的切入点称为JointPoint,该切入点由PointCut指定,不知道各位明白没有


beforeAdvice

在这里插入图片描述
在这里插入图片描述

大家可以联系spring aop aspectj的实现进行理解,但是不要将aop等同于spring aop aspectj.两者一个是抽象,一个是具体实现


AfterAdvice

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

aroundAdvice

在这里插入图片描述
在这里插入图片描述

Introduction

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Aspect

在这里插入图片描述
在这里插入图片描述

AspectJ风格定义的AspectJ声明 这里使用的是AspectJ的编译器对下面这个类进行的编译,然后再将编译生成的字节码对应被横切的java类源码中

代码语言:javascript
复制
public aspect MyAspectJDemo {
    /**
     * 定义切点,日志记录切点
     */
    pointcut recordLog():call(* HelloWord.sayHello(..));

    /**
     * 定义切点,权限验证(实际开发中日志和权限一般会放在不同的切面中,这里仅为方便演示)
     */
    pointcut authCheck():call(* HelloWord.sayHello(..));

    /**
     * 定义前置通知!
     */
    before():authCheck(){
        System.out.println("sayHello方法执行前验证权限");
    }

    /**
     * 定义后置通知
     */
    after():recordLog(){
        System.out.println("sayHello方法执行后记录日志");
    }
}
在这里插入图片描述
在这里插入图片描述

关于ajc编译器,是一种能够识别aspect语法的编译器,它是采用java语言编写的,由于javac并不能识别aspect语法,便有了ajc编译器,注意ajc编译器也可编译java文件。

在这里插入图片描述
在这里插入图片描述

织入和织入器

目标对象

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AOP王国底层运行机制

Spring AOP属于第二代AOP,采用动态代理机制和字节码生成技术实现,与最初Aspect采用编译器将横切逻辑织入目标对象不同,动态代理机制和字节码生成都是在运行期间为目标对象生成一个代理对象,而将横切逻辑织入到这个代理对象中,系统最终使用的是织入了横切逻辑的代理对象,而不是真正的目标对象。

为了理解这种差别以及最终可以达到的效果,我们有必要先从动态代理机制的根源----代理模式开始说起…


代理模式

之前在写设计模式专栏的时候,也写过一篇代理模式的介绍,感兴趣的童鞋可以了解一下:

代理模式

揭开动态代理的神秘面纱

在这里插入图片描述
在这里插入图片描述

静态代理

这里给出静态代理的一个简单的小例子:

代码语言:javascript
复制
public class Request {
    public void doGet() throws InterruptedException {
        System.out.println("处理请求中...");
        Thread.sleep(new Random().nextInt(10));
    }
}
代码语言:javascript
复制
public class RequestProxy extends Request{
    private Request request;

    public RequestProxy(Request request) {
        this.request = request;
    }

    @Override
    public void doGet() throws InterruptedException {
        long start = System.currentTimeMillis();
        request.doGet();
        long end = System.currentTimeMillis();
        System.out.println("当前请求耗时为: "+String.valueOf(end-start)+"毫秒");
    }
}
代码语言:javascript
复制
public class Main {
    public static void main(String[] args) throws InterruptedException {
       //没有被静态代理的类
        Request request=new Request();
        request.doGet();
       //被静态代理的类
       Request requestProxy=new RequestProxy(request);
       requestProxy.doGet();
    }
}
在这里插入图片描述
在这里插入图片描述

这个例子应该很容易看懂,这就对静态代理也就不过多介绍了,重点是对下面的动态代理进行介绍。

静态代理的缺点很明显: 虽然我们这里的Joinpoint相同(request()方法的执行),但是对应的目标对象类型是不一样的,针对不一样的目标对象类型,我们要为其单独实现一个代理对象,而实际上,这些代理对象所有添加的横切逻辑是一样的,当系统中存在大量符合Pointcut匹配条件的目标对象时,我们就需要为这些对象创建大量的代理对象,显然这是绝对行不通的!


动态代理

下面我们用JDK动态代理来实现一下上面的例子:

代码语言:javascript
复制
public interface IRequest {
    public void doGet() throws InterruptedException ;
}
代码语言:javascript
复制
public class Request implements IRequest{
    @Override
    public void doGet() throws InterruptedException {
        System.out.println("处理请求中...");
        Thread.sleep(new Random().nextInt(10));
    }
}
代码语言:javascript
复制
public class Main {
    public static void main(String[] args) throws InterruptedException {
        Request request=new Request();
        IRequest proxyInstance = (IRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(),
                request.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long start = System.currentTimeMillis();
                        Object invoke = method.invoke(request, args);
                        long end = System.currentTimeMillis();
                        System.out.println("请求耗时为 :" + String.valueOf(end - start) + "毫秒");
                        return invoke;
                    }
                });
      proxyInstance.doGet();
    }
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

默认情况下,Spring AOP发现目标对象实现了相应的接口,则采用动态代理机制为其生成代理对象实例,而如果没有的话,则会尝试使用CGLIB代为完成


动态字节码生成

在这里插入图片描述
在这里插入图片描述

小例子:

代码语言:javascript
复制
public class Request{
    public void doGet() throws InterruptedException {
        System.out.println("处理请求中...");
        Thread.sleep(new Random().nextInt(10));
    }
}
代码语言:javascript
复制
//实现MethodInterceptor接口
public class ProxyFactory implements MethodInterceptor
{
    //需要代理的目标对象
    private  Object target;

    public ProxyFactory(Object target)
    {
        this.target=target;
    }

    //获取代理对象的方法
    public Object getProxyInstance()
    {
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer=new Enhancer();
        // 设置enhancer对象的父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(target.getClass());
        //设置enhancer的回调对象
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    /**
     * @param o cglib生成的代理对象
     * @param method 被代理对象的方法
     * @param objects     传入方法的参数
     * @param methodProxy 代理的方法
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects,
                            MethodProxy methodProxy) throws Throwable {
        long start = System.currentTimeMillis();
        //这里必须传入被代理的对象,否则会死循环
        //因为代理对象方法调用会触发拦截器
        Object ret= method.invoke(target, objects);
        long end = System.currentTimeMillis();
        System.out.println("请求耗时为 :" + String.valueOf(end - start) + "毫秒");
        return ret;
    }
}
代码语言:javascript
复制
public class Main {
    public static void main(String[] args) throws InterruptedException {
        ProxyFactory proxyFactory=new ProxyFactory(new Request());
        Request proxyInstance = (Request) proxyFactory.getProxyInstance();
        proxyInstance.doGet();
    }
}
在这里插入图片描述
在这里插入图片描述

使用CGLIB对类进行扩展的唯一限制就是无法对final方法进行覆写


Spring aop 一世

Spring aop中的Joinpoint

在这里插入图片描述
在这里插入图片描述

Spring aop中的PointCut

在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public interface Pointcut {
    Pointcut TRUE = TruePointcut.INSTANCE;

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();
}
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
@FunctionalInterface
public interface ClassFilter {
    ClassFilter TRUE = TrueClassFilter.INSTANCE;

    boolean matches(Class<?> var1);
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public interface MethodMatcher {
    MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

    boolean matches(Method var1, Class<?> var2);

    boolean isRuntime();

    boolean matches(Method var1, Class<?> var2, Object... var3);
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

首先明确一点概念: PointCut是用来规定一组joinpoint的


常见的PointCut

在这里插入图片描述
在这里插入图片描述

NameMatchMethodPointcut
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public class NameMatchMethodPointcut extends StaticMethodMatcherPointcut implements Serializable {
    private List<String> mappedNames = new ArrayList();

    public NameMatchMethodPointcut() {
    }

    public void setMappedName(String mappedName) {
        this.setMappedNames(mappedName);
    }

    public void setMappedNames(String... mappedNames) {
        this.mappedNames = new ArrayList(Arrays.asList(mappedNames));
    }

    public NameMatchMethodPointcut addMethodName(String name) {
        this.mappedNames.add(name);
        return this;
    }

    public boolean matches(Method method, Class<?> targetClass) {
        Iterator var3 = this.mappedNames.iterator();

        String mappedName;
        do {
            if (!var3.hasNext()) {
                return false;
            }

            mappedName = (String)var3.next();
        } while(!mappedName.equals(method.getName()) && !this.isMatch(method.getName(), mappedName));

        return true;
    }

    protected boolean isMatch(String methodName, String mappedName) {
        return PatternMatchUtils.simpleMatch(mappedName, methodName);
    }
     .....
}

JdkRegexpMethodPointcut
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public class JdkRegexpMethodPointcut extends AbstractRegexpMethodPointcut {
    private Pattern[] compiledPatterns = new Pattern[0];
    private Pattern[] compiledExclusionPatterns = new Pattern[0];

    public JdkRegexpMethodPointcut() {
    }

    protected void initPatternRepresentation(String[] patterns) throws PatternSyntaxException {
        this.compiledPatterns = this.compilePatterns(patterns);
    }

    protected void initExcludedPatternRepresentation(String[] excludedPatterns) throws PatternSyntaxException {
        this.compiledExclusionPatterns = this.compilePatterns(excludedPatterns);
    }

    protected boolean matches(String pattern, int patternIndex) {
        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
        return matcher.matches();
    }

    protected boolean matchesExclusion(String candidate, int patternIndex) {
        Matcher matcher = this.compiledExclusionPatterns[patternIndex].matcher(candidate);
        return matcher.matches();
    }

    private Pattern[] compilePatterns(String[] source) throws PatternSyntaxException {
        Pattern[] destination = new Pattern[source.length];

        for(int i = 0; i < source.length; ++i) {
            destination[i] = Pattern.compile(source[i]);
        }

        return destination;
    }
}

AnnotationMatchingPointcut
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.TYPE)  
public @interface ClassLevelAnnotation {  

} 
 
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.METHOD)  
public @interface MethodLevelAnnotation {  

} 
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
@ClassLevelAnnotation  
public class TargetObject {  

    @MethodLevelAnnotation  
    public void method1() {  
        System.out.println("target : method1");  
    }  

    public void method2() {  
        System.out.println("target : method2");  
    }  
}  
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ComposablePointcut
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ControlFlowPointcut
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上面的pointcut对于方法的切入范围都相对来说比较宽泛,无法限制到只有方法在被指定类调用的时候,才会被织入切入的逻辑,而当前正在讲解的这个pointcut可以实现上面的需求

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

扩展pointcut
在这里插入图片描述
在这里插入图片描述

自定义StaticMethodMatcherPointcut
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

自定义DynamicMethodMatcherPointcut
在这里插入图片描述
在这里插入图片描述

IOC容器中的pointcut

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Spring AOP中的Adivce

pointcut负责找到所有符合条件的joinpoint,然后由织入器将advice里面的横切逻辑织入到这些joinpoint中去

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

per-class类型的Advice

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

before advice
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ThrowsAdvice
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

AfterReturningAdvice
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public interface AfterReturningAdvice extends AfterAdvice {
	void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
在这里插入图片描述
在这里插入图片描述

Around Advice
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
@FunctionalInterface
public interface MethodInterceptor extends Interceptor {
	@Nullable
	Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

per-instance类型的Advice

在这里插入图片描述
在这里插入图片描述

Introduction
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public interface IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice {
}
代码语言:javascript
复制
public interface DynamicIntroductionAdvice extends Advice {
	boolean implementsInterface(Class<?> intf);
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码语言:javascript
复制
public interface IntroductionInfo {
	Class<?>[] getInterfaces();
}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DelegatingIntroductionInterceptor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DelegatePerTargetObjectIntroductionInterceptor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Spring AOP中的Aspect

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

PointcutAdvisor

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DefaultPointcutAdvisor
在这里插入图片描述
在这里插入图片描述

Generic: 通用的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

NameMatchMethodPointcutAdvisor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RegexpMethodPointcutAdvisor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

DefaultBeanFactoryPointcutAdvisor
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

IntroductionAdvisor分支

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Ordered作用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring繁华的AOP王国---第一讲
  • 为什么需要AOP
  • AOP国家的公民
    • JoinPoint
      • PointCut
        • PointCut表达式
        • pointcut运算
      • Advice
        • beforeAdvice
        • AfterAdvice
        • aroundAdvice
        • Introduction
      • Aspect
        • 织入和织入器
          • 目标对象
          • AOP王国底层运行机制
            • 代理模式
              • 静态代理
              • 动态代理
              • 动态字节码生成
          • Spring aop 一世
            • Spring aop中的Joinpoint
              • Spring aop中的PointCut
                • 常见的PointCut
                • IOC容器中的pointcut
              • Spring AOP中的Adivce
                • per-class类型的Advice
                • per-instance类型的Advice
              • Spring AOP中的Aspect
                • PointcutAdvisor
                • IntroductionAdvisor分支
              • Ordered作用
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档