热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Spring框架学习之AOP详解

这篇文章主要介绍了Spring框架学习之AOP详解,文中有非常详细的代码示例,对正在学习Spring框架的小伙伴们有一定的帮助,需要的朋友可以参考下

一、概念

1.面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

2.通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

二、底层原理:动态代理

有两种情况动态代理

2.1 有接口, JDK 动态代理

1.被代理的对象

public class UserDaoImpl implements UserDao {

    @Override
    public int add(int a, int b) {
        System.out.println("add执行");
        return a + b;
    }

    @Override
    public String update(String id) {
        System.out.println("update执行");
        return id;
    }

}

2.代理

package cn.zj.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

import cn.zj.dao.UserDao;
import cn.zj.dao.impl.UserDaoImpl;

public class JDKProxy {

    public static void main(String[] args) {
        // 创建接口实现类代理对象
        Class[] interfaces = { UserDao.class };
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces,
                new UserDaoProxy(userDao));
        
        int result = dao.add(1, 2);
        System. out .println( "result:"+result);
    }
}

//创建代理对象代码
class UserDaoProxy implements InvocationHandler {

    private Object target;// 目标类

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法执行之前
        System.out.println("方法执行之前.." + method.getName() + ";传递的参数:" + Arrays.toString(args));
        // 增强方法
        Object res = method.invoke(target, args);
        // 方法执行之后
        System.out.println("方法执行之后.." + target);
        return res;
    }

}

3.打印

方法执行之前..add;传递的参数:[1, 2]
add执行
方法执行之后..cn.zj.dao.impl.UserDaoImpl@6c629d6e
result:3

2.2 无接口, CGLIB 动态代理

1.被代理的对象

public class Cat {

    public void eat() {
        System.out.println("猫吃鱼");
    }
}

2.代理

public class CglibProxy {

    public static void main(String[] args) {
        Cat c = new CglibProxy().createProxyObject(Cat.class);
        c.eat();
    }

    // JDK代理是对对象做代理,cglib代理是对类做代理
    public Cat createProxyObject(Class clazz) {
        // 1.创建内存中的动态类 Enhance
        // 内存中造出一个没有名称的动态类
        Enhancer enhancer = new Enhancer();
        // 2.现在的类最终完成原始类的功能,同时对其进行功能的增强,必须先具有原始类对应的功能————继承
        enhancer.setSuperclass(clazz);
        // 3.进行功能的增强
        // 设置了方法的调用拦截
        // 设置具体的回调操作
        Callback callback = new MethodInterceptor() {
            // proxy:代理对象
            // method:被拦截的方法对象
            // args:调用参数
            // methodProxy:
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
                    throws Throwable {
                // 做增强
                System.out.println("执行前");
                // Object obj=method.invoke(proxy, args);//这种执行是代理类的方法,而不是目标类的,会造成内存溢出
                // 以下的两种都是执行目标类的方法
                // Object obj = methodProxy.invokeSuper(proxy, args);//执行目标类的方法
                // Object obj=method.invoke(proxy, args);
                Object res = methodProxy.invokeSuper(proxy, args);
                System.out.println("执行后");
                return res;
            }
        };
        enhancer.setCallback(callback);
        // 4.创建内存中的全新的类的对象
        Object proxyObj = enhancer.create();
        return (Cat) proxyObj;
    }

}

三、术语

1.连接点(Joinpoint)

类中的任意方法的运行时表示,可以简单理解为类中的方法,也就是可以被增强的方法

2.切入点(Pointcut)

具有共性功能的方法的运行时表示,可以简单理解为具有共性功能的方法,也就是实际被增强的方法

注意:切入点对应的是被挖去了共性功能后的方法执行时匹配断言(格式)

3.通知/增强(Advice)

共性功能模块化,可以简单理解为将共性功能抽取出来制作成独立的方法,实际增强的逻辑部分

类型:前置,后置,异常,最终,环绕

4.切面(Aspect)

切入点与通知的对应关系,可以简单理解为被抽取的共性功能与共性功能被抽取位置对应的方法之间的关系,把通知应用到切入点的过程

5.目标对象(Target Object)

包含切入点的运行时对象,开发阶段制作的是目标对象对应的类

6.AOP代理(AOP Proxy)

使用AOP的代理机制创建目标对象运行时代理对象,完成原始的功能

注意:原始目标对象已经被挖去了共性功能,此时使用目标对象执行任务无法完成原始任务,使用AOP代理机制,创建一个代理对象来完成原始目标对象的功能

7.织入(Weaving)

是一个将通知功能加入原始字节码的动态过程,将增强添加对目标类具体连接点上的过程

Spring使用的是运行时织入机制

8.引入(Introduction)

一种特殊的机制,可以为一个类的字节码动态的加入变量或方法

四、操作

4.1 Spring 框架一般都是基于 AspectJ 实现 AOP

AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使

用,进行 AOP 操作

4.2 实践

 1.jar包引入



        
            org.springframework
            spring-core
            5.3.6
        
        
            org.springframework
            spring-beans
            5.3.6
        
        
            org.springframework
            spring-context
            5.3.6
        
        
        
            org.springframework
            spring-expression
            5.3.6
        



        
        
            org.springframework
            spring-aop
            5.3.6
        

        
        
            commons-logging
            commons-logging
            1.2
        

        
        
            com.alibaba
            druid
            1.2.6
        

        
        
            javax.annotation
            javax.annotation-api
            1.3.1
        


        
        
            org.springframework
            spring-aspects
            5.3.6
        

        
        
            net.sourceforge.cglib
            com.springsource.net.sf.cglib
            2.2.0
        
        
        
            org.aopalliance
            com.springsource.org.aopalliance
            1.0.0
        
        
        
            org.aspectj
            com.springsource.org.aspectj.weaver
            1.6.8.RELEASE
        



    

2.切入点表达式

作用:知道对哪个类里面的哪个方法进行增强

语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 )

举例 1:对 com.zj.dao.BookDao 类里面的 add 进行增强

execution(* com.zj.dao.BookDao.add(…))

举例 2:对 com.zj.dao.BookDao 类里面的所有的方法进行增强

execution(* com.zj.dao.BookDao.* (…))

举例 3:对 com.zj.dao 包里面所有类,类里面所有方法进行增强

execution(* com.zj.dao.. (…))

3.xml方式

1.创建类

package cn.zj.aop.xml;

public class Book {
    public void buy() {
        System.out.println("buy.............");
    }
}

2.增强类

package cn.zj.aop.xml;

public class BookProxy {
    public void before() {
        System.out.println("before.........");
    }
}

3.xml

<&#63;xml version="1.0" encoding="UTF-8"&#63;>

    
    
    

    
    
        
        
        
        
            
            
        
    

4.注解方式

1.创建类

public class User {
    public void add() {
        System.out.println("add.......");
    }

}

2.创建增强类

package cn.zj.aop.an;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

//增强的类
@Component
@Aspect  //生成代理对象

public class UserProxy {

    //前置通知
    @Before(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void before() {
        System.out.println("before.........");
    }

    //后置通知(返回通知)
    @AfterReturning(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void afterReturning() {
        System.out.println("afterReturning.........");
    }

    //最终通知
    @After(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void after() {
        System.out.println("after.........");
    }

    //异常通知
    @AfterThrowing(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing.........");
    }

    //环绕通知
    @Around(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕之前.........");

        //被增强的方法执行
        proceedingJoinPoint.proceed();

        System.out.println("环绕之后.........");
    }
}

3.xml配置注解扫描

<&#63;xml version="1.0" encoding="UTF-8"&#63;>

    
    

    
    

4.测试

ApplicationContext cOntext= new ClassPathXmlApplicationContext("bean1.xml");
        User user = context.getBean("user", User.class);
        user.add();

5.相同点抽取

//相同切入点抽取
    @Pointcut(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void pointdemo() {

    }

    //前置通知
    //@Before注解表示作为前置通知
    @Before(value = "pointdemo()")
    public void before() {
        System.out.println("before.........");
    }

6.有多个增强类多同一个方法进行增强,设置增强类优先级

在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高

@Component
@Aspect 
@Order(1)
public class PersonProxy {

     //后置通知(返回通知)
    @Before(value = "execution(* cn.zj.aop.an.User.add(..))")
    public void afterReturning() {
        System.out.println("Person Before.........");
    }
}
//增强的类
@Component
@Aspect  //生成代理对象
@Order(2)
public class UserProxy {

到此这篇关于Spring框架学习之AOP详解的文章就介绍到这了,更多相关Spring框架AOP内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
  • 本文详细介绍了如何使用PHP检测AJAX请求,通过分析预定义服务器变量来判断请求是否来自XMLHttpRequest。此方法简单实用,适用于各种Web开发场景。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何解决MyBatis中常见的BindingException错误,提供了多种排查和修复方法,确保Mapper接口与XML文件的正确配置。 ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
author-avatar
最好的zixue
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有