Spring-AOP学习笔记

Spring 是轻量级的开源的 JavaEE 框架。

Spring有两个核心部分IOC 和 Aop

  1. IOC(Inversion of Control):控制反转,把创建对象过程交给 Spring 进行管理
  2. Aop(Aspect Oriented Programming):面向切面编程,不修改源代码进行功能增强

Spring特点:

  1. 方便解耦,简化开发
  2. Aop 编程支持
  3. 方便程序测试
  4. 方便和其他框架进行整合
  5. 方便进行事务操作
  6. 降低 API 开发难度

本篇介绍主要介绍AOP

底层原理

AOP的底层使用动态代理。动态代理有两种情况,一种为有接口的情况(使用JDK动态代理),一种为没有接口的情况(使用CGLIB动态代理)下面介绍的是有接口的情况

使用JDK动态代理:

关键方法 newProxyInstance(ClassLoader loader, class<?>[] interfaces, InvocationHandler h)

该方法返回指定接口的代理实例。 loader:用户定义代理类的类加载器; interfaces :要实现的代理类的接口列表; h:实现InvocationHandler的类,在重写的invoke方法中加入自己增强的代码部分。

使用Proxy类创建UserDao接口代理对象的代码如下,UserDao为自己定义的一个接口,接口中有一个add方法,UserDaoImpl为接口实现类,

public class JDKProxy {
    public static void main(String[] args) {
        Class[] interfaces = {UserDao.class};
        UserDaoImpl userDaoImpl = new UserDaoImpl();
        //创建接口实现类代理对象
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoImpl));
        //测试
        dao.add(1, 2);
    }
}

//创建代理对象
class UserDaoProxy implements InvocationHandler{
    private Object object;
    //有参构造器传递对象
    public UserDaoProxy(Object object){
        this.object = object;
    }
    //写增强的逻辑,在与其关联的代理实例上调用方法时,invoke方法就会被调用
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //原方法之前执行代码
        System.out.println("原方法之前执行..."+"执行的方法为:"+ method.getName()+"...传递的参数为:"+ Arrays.toString(args));
        //原方法
        Object res = method.invoke(object, args);
        //原方法之后执行代码
        System.out.println("原方法之后执行...");
        return res;
    }
}

运行结果如下:

Spring-AOP学习笔记

自己的白话总结:创建 InvocationHandler 接口的实现类并重写 invoke 方法,在 invoke 方法中添加自己的代码增强部分。调用 newProxyInstance 返回代理实例并向上转型为接口,当我们调用接口中的方法时,就调用了 invoke 方法,从而实现了代码的功能增强。如有错误请指正

AOP操作实现

Spring 框架一般都是基于 AspectJ 实现 AOP 操作,AspectJ 不是 Spring 组成部分,它是独立的 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP 操作。

基于 AspectJ 实现 AOP 操作有两种方式:

  • 基于xml配置文件实现
  • 基于注解方式实现(常用)

相关术语与切入点表达式

  • 连接点:可以被增强的方法
  • 切入点:被增强的方法
  • 通知:实际增强的逻辑部分(说人话:自己要添加的代码) 通知的类型:
  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知
  • 切面:把通知应用到切入点的过程(说人话:把增强的代码应用到原方法中)

切入点表达式:

切入点表达式的作用:知道对哪个类里面的哪个方法进行增强

语法结构: execution([&#x6743;&#x9650;&#x4FEE;&#x9970;&#x7B26;] [&#x8FD4;&#x56DE;&#x7C7B;&#x578B;] [&#x7C7B;&#x5168;&#x8DEF;&#x5F84;] [&#x65B9;&#x6CD5;&#x540D;&#x79F0;]([&#x53C2;&#x6570;&#x5217;&#x8868;]) )

相关示例如下:

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

execution(* com.hnust.spring5.dao.BookDao.add(..))

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

execution(* com.hnust.spring5.dao.BookDao.* (..))

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

execution(* com.hnust.spring5.dao.*.* (..))

基于注解方式实现AOP

导入相关jar包,以下作为参考

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.jar
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar

创建普通类

@Component//该注解实现bean注入
public class User {
    public void add(){
        System.out.println("add....");
    }
}

创建增强类,这里展示前置通知,最终通知,后置通知,异常通知和环绕通知

@Component
@Aspect //生成代理对象
public class UserProxy {
    //前置通知
    @Before(value = "execution(* com.hnust.spring5.aopanno.User.add(..))")
    public void before(){
        System.out.println("before....");
    }

    //最终通知
    @After(value = "execution(* com.hnust.spring5.aopanno.User.add(..))")
    public void after(){
        System.out.println("after...");
    }

    //后置通知(返回通知)
    @AfterReturning(value = "execution(* com.hnust.spring5.aopanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning...");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.hnust.spring5.aopanno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing...");
    }

    //环绕通知
    @Around(value = "execution(* com.hnust.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint){
        System.out.println("环绕之前");
        //执行原方法
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("环绕之后");
    }
}

xml配置


创建测试类

@Test
public void testAopAnno(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    User user = context.getBean("user", User.class);
    user.add();
}

执行结果:

Spring-AOP学习笔记

前置通知,在方法执行之前执行;

最终通知,在方法执行之后执行;

后置通知(返回通知),在方法返回结果之后执行;

异常通知,在方法抛出异常之后执行;

环绕通知,围绕着方法执行。

关于最终通知和后置通知可能会有概念上的区别,以自己学的实际为准。

如果有多个增强类对同一个方法进行增强,可以通过添加注解 @Order(&#x6570;&#x5B57;)来设置优先级,数字越小,优先级越高。

操作数据库

Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作

首先引入相关jar包,具体版本根据自己的实际版本为准,以下为参考

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
mysql-connector-java-5.1.7-bin.jar
spring-aop-5.2.6.RELEASE.jar
spring-aspects-5.2.6.RELEASE.jar
spring-beans-5.2.6.RELEASE.jar
spring-context-5.2.6.RELEASE.jar
spring-core-5.2.6.RELEASE.jar
spring-expression-5.2.6.RELEASE.jar
spring-jdbc-5.2.6.RELEASE.jar
spring-orm-5.2.6.RELEASE.jar
spring-tx-5.2.6.RELEASE.jar

配置xml文件


编写dao层代码,以下示例只展示了dao层的部分实现类,其他的功能大同小异。都学到这里了,service层肯定都会写,我就不再贴出来了。

@Service
public class BookDaoImpl implements BookDao{

    //注入JdbcTemplate
    @Autowired
    private JdbcTemplate jdbcTemplate;
    //添加
    @Override
    public void add(Book book) {
        String sql = "insert into t_book values(?, ?, ?)";
        Object[] args = {book.getUser_id(), book.getUsername(), book.getUstatus()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }
    //修改
    @Override
    public void updateBook(Book book) {
        String sql = "update t_book set username=?, ustatus=? where user_id=?";
        Object[] args = {book.getUsername(), book.getUstatus(), book.getUser_id()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }
    //删除
    @Override
    public void deleteBook(Integer id) {
        String sql = "delete from t_book where user_id=?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }
    //查询
    @Override
    public Book findOne(Integer id) {
        String sql = "select * from t_book where user_id=?";
        return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Book.class),id);
    }
}

测试

public class TestBook {
    @Test
    public void testJdbcTemplate(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        BookServiceImpl bookServiceImpl = context.getBean("bookServiceImpl", BookServiceImpl.class);
        //添加
//        bookServiceImpl.addBook(new Book(1,"java", "on"){});
        //修改
//        bookServiceImpl.updateBook(new Book(1,"c++","off"));
        //删除
//        bookServiceImpl.deleteBook(1);
        //查询
//        System.out.println(bookServiceImpl.findOne(1));
        }
}

Original: https://www.cnblogs.com/xuzhuo123/p/15717004.html
Author: 在锻炼的新生代农民工
Title: Spring-AOP学习笔记

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/586616/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 进程和线程的对比和区别

    进程中包括有多个线程,进程与进程之间是相对比较独立的。 进程中有一个 逻辑内存,每个进程都会有分配到一个独立的内存空间,还分配了一个文件/网络句柄, 句柄类似一个标识符,所有的进程…

    Java 2023年5月30日
    068
  • 如何在电脑上配置Vue开发环境

    一,开发环境 : Node JS(npm) Visual Studio Code(前端IDE) 安装NodeJS 下载地址: nodejs中文网 Visual Studio Cod…

    Java 2023年6月15日
    083
  • 分享一个基于 netty 的 java 开源项目

    1、简介 中微子代理(neutrino-proxy)是一个基于 netty 的、开源的 java 内网穿透项目。遵循 MIT 许可,因此您可以对它进行复制、修改、传播并用于任何个人…

    Java 2023年6月8日
    072
  • JVM集合之开篇点题

    大家在平时的开发过程中是否遇到过 StackOverflowError、 OutOfMemoryError等类似的内存溢出错误呢?大家又是怎么解决这个问题的?再来,大家在面试过程中…

    Java 2023年6月5日
    090
  • map和flatMap的区别

    转自: Optional 类简介: Java8 新增了非常多的特性,而Optional 类就是其中一个新增的类 Optional 类是一个可以为null的容器对象。如果值存在则is…

    Java 2023年6月15日
    080
  • Spring 容器的启动过程 流程图 自己看源码的梳理 如有错错误 请指正

    Original: https://www.cnblogs.com/pupansheng/p/15666070.htmlAuthor: 蒲蒲的博客Title: Spring 容器的…

    Java 2023年6月5日
    079
  • Spring-AOP

    AOP操作 百度百科:在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一…

    Java 2023年6月8日
    089
  • 【Java面试手册-算法篇】给定一个整数,输出逆序数字

    输出逆序数字相当于反转数字,比如1234,逆序后为4321,在反转数字时,需要注意反转后得到的数字是否会超过最大范围,比如int最大值为2147483647,正常反转后的值是746…

    Java 2023年6月8日
    085
  • java 4舍5入

    /** * @Dscription: scale,保留几位小数点 molecular 分子,denominator 分母 * @Author: zyn * @Date: 2021/…

    Java 2023年5月29日
    079
  • Halo 开源项目学习(二):实体类与数据表

    基本介绍 Halo 项目中定义了一些实体类,用于存储博客中的关键数据,如用户信息、文章信息等。在深入学习 Halo 的设计理念与实现过程之前,不妨先学习一下一个完整的博客系统都由哪…

    Java 2023年6月9日
    093
  • 【软件构造】Java设计模式

    创建模式:关注对象的创建过程 简单工厂模式 实现流程: 将需要创建的各种不同的产品对象封装到不同的类中,成为具体产品类 将具体产品类的公共代码进行提取封装到抽象产品类中,具体产品类…

    Java 2023年6月5日
    078
  • 15分钟学会JWT使用

    什么是JWT? JSON Web Token ,通过数字签名的方式,以JSON对象为载体,在不同的服务终端之间安全的传输信息。 jwt 可以生成 一个加密的token,做为用户登录…

    Java 2023年6月9日
    071
  • Solr集群搭建详细教程(二)

    注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com。 三、solr集群搭建 注意,在搭建solr集群前…

    Java 2023年6月9日
    082
  • Spring5 学习笔记

    学习地址: B站-动力节点 个人代码: GitHub Spring 概述 1.1 Spring 简介 Spring Framework 是一个使用Java开发的、轻量级的、开源框架…

    Java 2023年6月5日
    080
  • 解决Mybatis-plus高版本不向后兼容的问题

    mybatis-plus插件后面的版本没有兼容低版本。即:不存在低版本中EntityWrapper这个类了。而该类采用数据库表真实字段名作查询条件,这样硬编码形式确实不友好,比如如…

    Java 2023年6月5日
    077
  • Maven-私服搭建与配置

    一、maven私服搭建 1.下载地址 https://help.sonatype.com/repomanager3/product-information/download/dow…

    Java 2023年6月9日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球