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
134 0
|
XML Java 数据格式
spring太强了!两万多字干货 超详细讲解(二)
spring太强了!两万多字干货 超详细讲解
|
XML Java Maven
spring太强了!两万多字干货 超详细讲解(一)
spring太强了!两万多字干货 超详细讲解
|
消息中间件 分布式计算 数据可视化
Spring Boot + 规则引擎 URule,太强了!
Spring Boot + 规则引擎 URule,太强了!
|
Java Docker 容器
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
首先说一下从零开始自己去搭一个fastdfs挺麻烦,后来看到有人把做好的 docker 镜像传出来了,那搭建起来就很容易了
212 0
Docker + Spring Boot + FastDFS 搭建一套分布式文件服务器,太强了
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
8天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
19 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
4天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
15 2