spring太强了!两万多字干货 超详细讲解(三)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: spring太强了!两万多字干货 超详细讲解

4.3 Spring API接口实现


  • Aop是什么?一般情况下,在程序执行时,是从上到下执行的
  • 如果要在执行的某个点,插入一个功能,如何实现?
  • 比如一个系统,我需要加入逻辑删除,我需要增加日志功能,难道我去修改原有代码?
  • 这就需要我们使用Aop来实现横向切入,增加功能!


我们以增加日志功能为例,介绍Aop的实现流程之一 —— 基于Spring API接口实现


编写一个Service

public interface BookService {
    void add();
    void delete();
    void update();
    void select();
}


编写Service的实现类

public class BookServiceImpl implements BookService {
    public void add() {
        System.out.println("增加了一本书");
    }
    public void delete() {
        System.out.println("删除了一本书");
    }
    public void update() {
        System.out.println("修改了一本书");
    }
    public void select() {
        System.out.println("查询了一本书");
    }
}


编写方法前日志

public class BeforeLog implements MethodBeforeAdvice {
    /**
     * method要执行的目标对象的方法
     * args 参数
     * target 目标对象
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + " 的 "+method.getName() + " 被执行了!");
    }
}


编写方法后日志

public class AfterLog implements AfterReturningAdvice {
    /**
     * returnValue  返回对象
     * method要执行的目标对象的方法
     * args 参数
     * target 目标对象
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了 " +method.getName() + " 方法, 返回结果为" + returnValue);
    }
}


配置文件配置切面、切入点

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <bean id="bookService" class="zwz.demo1.service.BookServiceImpl"/>
    <bean id="beforeLog" class="zwz.demo1.log.BeforeLog"/>
    <bean id="afterLog" class="zwz.demo1.log.AfterLog"/>
    <!--配置AOP-->
    <aop:config>
        <!-- 切入点-->
        <aop:pointcut id="pointcut" expression="execution(* zwz.demo1.service.BookServiceImpl.*(..))"/>
        <!--执行环绕增加 ,将beforeLog切入到pointcut中 -->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>


测试

@Test
public void testAop1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookService bookService = (BookService) context.getBean("bookService");
    bookService.add();
}

这样,我们就实现了在执行某个方法的时候,输出日志的功能了


输出结果

zwz.demo1.service.BookServiceImpl 的 add 被执行了!
增加了一本书
执行了 add 方法, 返回结果为null
Process finished with exit code 0


4.4 自定义类实现


接下来是基于自定义类接口实现,和spring的API实现一样,先写业务的实现接口和实现类

public interface BookService2 {
    void add();
    void delete();
    void update();
    void select();
}
public class BookServiceImpl2 implements BookService2 {
    public void add() {
        System.out.println("增加了一本书");
    }
    public void delete() {
        System.out.println("删除了一本书");
    }
    public void update() {
        System.out.println("修改了一本书");
    }
    public void select() {
        System.out.println("查询了一本书");
    }
}


和spring API方法一致,编写两个切入日志类

public class BeforeLog implements MethodBeforeAdvice {
    /**
     * method要执行的目标对象的方法
     * args 参数
     * target 目标对象
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + " 的 "+method.getName() + " 被执行了!");
    }
}
public class AfterLog implements AfterReturningAdvice {
    /**
     * returnValue  返回对象
     * method要执行的目标对象的方法
     * args 参数
     * target 目标对象
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了 " +method.getName() + " 方法, 返回结果为" + returnValue);
    }
}


编写自定义切入类

public class DiyPointCut {
    public void before(){
        System.out.println("==============方法执行前==============");
    }
    public void after(){
        System.out.println("==============方法执行后==============");
    }
}


配置文件

<bean id="bookService2" class="zwz.demo2.service.BookServiceImpl2"/>
<!--方式二:采用自定义类 配置AOP-->
<bean id="diy" class="zwz.demo2.diy.DiyPointCut"/>
<aop:config>
    <!-- 自定义切面  ref要引用的类-->
    <aop:aspect ref="diy">
        <!-- 切入点-->
        <aop:pointcut id="point" expression="execution(* zwz.demo2.service.BookServiceImpl2.*(..))"/>
        <!-- 通知-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>


测试

@Test
    public void testAop2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService2 bookService2 = (BookService2) context.getBean("bookService2");
        bookService2.add();
    }
==============方法执行前==============
增加了一本书
==============方法执行后==============


4.5 Java注解实现


和之前两个方法一样,先写Service服务层的接口和实现类

public interface BookService3 {
    void add();
    void delete();
    void update();
    void select();
}
public class BookServiceImpl3 implements BookService3 {
    public void add() {
        System.out.println("增加了一本书");
    }
    public void delete() {
        System.out.println("删除了一本书");
    }
    public void update() {
        System.out.println("修改了一本书");
    }
    public void select() {
        System.out.println("查询了一本书");
    }
}


切面类

@Aspect  //标注这个类是一个切面
public class PointCut {
    @Before("execution(* zwz.demo3.service.BookServiceImpl3.*(..))")
    public void before(){
        System.out.println("==============方法执行前==============");
    }
    @After("execution(* zwz.demo3.service.BookServiceImpl3.*(..))")
    public void after(){
        System.out.println("==============方法执行后==============");
    }
}


配置文件

<!--方式三:采用注解 配置AOP-->
<bean id="bookService3" class="zwz.demo3.service.BookServiceImpl3"/>
<bean id="pointCut" class="zwz.demo3.cut.PointCut"/>
<!--开启注解支持  默认JDK实现(proxy-target-class="false")||  也有cglib-->
<aop:aspectj-autoproxy/>


测试类

@Test
public void testAop3(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    BookService3 bookService3 = (BookService3) context.getBean("bookService3");
    bookService3.add();
}


输出结果

==============方法执行前==============
增加了一本书
==============方法执行后==============


五、总结


5.1 总结&附录


spring是一个粘合剂,可以整合其他优秀的框架,大大简化了软件开发的复杂度

我认为spring的核心内容:

  • IOC控制反转
  • AOP面向切面编程

其他内容比如整合mybatis、声明式事务,在后续再写。



5.2 模板文件


applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
</beans>


mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="zwz.pojo"/>
    </typeAliases>
    <environments default="zwz">
        <environment id="zwz">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper class="zwz.mapper.UserMybatisMapper"></mapper>
    </mappers>
</configuration>


5.3 spring配置标签


bean

bean用来注册实体类,可以注入相应的变量值

<bean id="user" class="zwz.pojo.User">
    <property name="name" value="ZWZ"/>
    <property name="age" value="18"/>
</bean>


alias


设置别名,设置后原名和别名都可以使用

bean 中的 name 属性也可以做别名,而且功能更加强大

<bean id="user" class="zwz.pojo.User">
    <property name="name" value="ZWZ"/>
    <property name="age" value="18"/>
</bean>
<alias name="user" alias="userZwz"/>

可以在测试类中这样调用别名bean

// ApplicationContext Spring上下文对象 | ClassPathXmlApplicationContext 从配置文件中去取
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 从容器中取出user对象
User user = (User) context.getBean("userZwz");


import

在团队开发中,每个人都需要拥有自己的配置文件,可以通过import标签将多个配置文件整合成一个

如张三的配置文件 —— bean1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="zwz.pojo.User">
        <!-- property相当于给某个变量设置一个值-->
        <property name="name" value="ZWZ"/>
        <property name="age" value="18"/>
    </bean>
    <alias name="user" alias="userZwz"/>
</beans>

团队整体的配置文件 —— applicationContext.xml,可以将所有人的配置文件合并成一个总的

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="bean1.xml"/>
</beans>


context

自动装配bean

<context:annotation-config/>

扫描指定包的组件

<!--指定要扫描的包 这个包下的注解就会生效-->
<context:component-scan base-package="zwz"/>
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
安全 Java 测试技术
Github标星98k,Alibaba最新发布的Spring Boot项目实战文档!太强了
前言 又到了一年一度的备战秋招的时间,虽然这两年因为经济环境不太好,互联网行业的各大厂都再裁员,但是今年的秋招经济形势正在复苏,我特地拜托阿里的朋友将这份Spring Boot项目实战开发文档分享出来。 本文档涵盖Spring Boot企业级项目开发的各方面知识,重点介绍Maven项目的搭建、Jersey Restful风格、Postman测试接口、Swagger2可视化文档、Lombok优雅编码、Redis缓存、Security安全机制、Web Service服务、WebSocke t通信、性能测试、集成测试、Jeecg Boot快速开发框架、使用Docker进行项目部署、使
|
安全 Java 测试技术
Github标星98k,Alibaba最新发布的Spring Boot项目实战文档!太强了
前言 又到了一年一度的备战秋招的时间,虽然这两年因为经济环境不太好,互联网行业的各大厂都再裁员,但是今年的秋招经济形势正在复苏,我特地拜托阿里的朋友将这份Spring Boot项目实战开发文档分享出来。 本文档涵盖Spring Boot企业级项目开发的各方面知识,重点介绍Maven项目的搭建、Jersey Restful风格、Postman测试接口、Swagger2可视化文档、Lombok优雅编码、Redis缓存、Security安全机制、Web Service服务、WebSocke t通信、性能测试、集成测试、Jeecg Boot快速开发框架、使用Docker进行项目部署、使用sp
157 0
|
XML Java 数据格式
spring太强了!两万多字干货 超详细讲解(二)
spring太强了!两万多字干货 超详细讲解
|
XML Java Maven
spring太强了!两万多字干货 超详细讲解(一)
spring太强了!两万多字干货 超详细讲解
107 0
|
消息中间件 分布式计算 数据可视化
Spring Boot + 规则引擎 URule,太强了!
Spring Boot + 规则引擎 URule,太强了!
|
Java Docker 容器
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
首先说一下从零开始自己去搭一个fastdfs挺麻烦,后来看到有人把做好的 docker 镜像传出来了,那搭建起来就很容易了
222 0
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
277 2
|
6天前
|
Java 测试技术 应用服务中间件
Spring Boot 如何测试打包部署
本文介绍了 Spring Boot 项目的开发、调试、打包及投产上线的全流程。主要内容包括: 1. **单元测试**:通过添加 `spring-boot-starter-test` 包,使用 `@RunWith(SpringRunner.class)` 和 `@SpringBootTest` 注解进行测试类开发。 2. **集成测试**:支持热部署,通过添加 `spring-boot-devtools` 实现代码修改后自动重启。 3. **投产上线**:提供两种部署方案,一是打包成 jar 包直接运行,二是打包成 war 包部署到 Tomcat 服务器。
28 10
|
20天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
7天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
36 8