Java零基础——Spring篇

1.Spring框架的介绍

1.1 传统的项目的架构

在这里插入图片描述

在传统的项目中,一般遵循MVC开发模型。

(1) view层与用户进行交互,显示数据或者将数据传输给view层。

(2) 在controller层创建service层对象,调用service层中业务方法。

(3) 在service层创建dao层对象,调用dao层中操作数据的方法。

(4) dao层进行具体的数据库操作

1.2 传统的项目架构缺陷

程序在一定程度上存在耦合性,不利于程序的扩展。在controller中直接创建了service层类的对象。如果service的业务发生了变更,那么就需要修改controller层的代码。
在这里插入图片描述

在进行程序的扩展时,不建议在当前程序的基础上直接修改程序,为了保证之前程序的正常,一般遵循开闭原则进行维护性的修改,对扩展开放,对修改关闭。

例如:用户注册功能。用户注册,从账号、密码、手机号等信息即可。随着行业发展,目前要求进行实名认证。

1.已注册未认证用户登录时进行认证。

2.新用户注册后要求进行认证。

为避免对已有业务的改动,可以新建一个service类,重写注册方法。则在controller层需要创建新的service对象。每个相关的controller层的代码都需要改动,并且每个controller都需要创建对象,存在对象的浪费。

面向过程—>面向对象---->面向接口---->面向切面(组件)

ArrayList aList = new ArrayList();

List aList = new LinkedList()

1.3 解决方案

基于每个controller都要修改service的创建问题,可以为service定义一个统一的创建方式,例如对象工厂模式,使用工厂创建对象,这样以后使用工厂创建对象的对象需要维护时,只需要修改对象工厂即可,且可以结合单例模式,对象工厂返回单例,这样优化了对象重复的浪费问题。
在这里插入图片描述

虽然单例工厂能够解决对象的维护和重复问题。但是,随着service层的扩大,工厂也逐渐臃肿,基本每个service会对应一个factory。基于这种情况,则又需要解决工厂臃肿的问题,为此可以利用反射技术,反射可以创建任意类的对象。但是,工厂为保证单例,只能存储的对象只有一个,而controller层需要使用不同的service层对象,为保证对象的有效,且反射性能相对较低,基于这样的情况,则可以定义一个需要创建的对象的清单和一个存储对象的容器,根据清单创建对象,然后将所有创建service对象进行存储,每个controller只需要去容器中获取对象即可,这样既解决了单例问题,也提高了性能。
在这里插入图片描述

1.3.1 代码示例
在这里插入图片描述

1.3.2 对象清单
在这里插入图片描述
在这里插入图片描述

1.3.3 对象容器工厂

package org.springframework.context;public interface ApplicationContext {/*** 获取spring容器创建好的对象* @param name* @return*/Object getBean(String name);/*** 获取spring容器创建好的对象* @param name* @return*/<T> T getBean(String name,Class<T> c);}package org.springframework.context.support;import org.dom4j.Document;import org.dom4j.Element;import org.dom4j.io.SAXReader;import org.springframework.context.ApplicationContext;import java.io.InputStream;import java.util.HashMap;import java.util.List;import java.util.Map;/*** spring的核心类*/public class ClassPathXmlApplicationContext implements ApplicationContext {/*** 用于存放id或者name与某个类对象的映射关系*/private Map<String,Object> objMap = new HashMap<>();public ClassPathXmlApplicationContext(){}public ClassPathXmlApplicationContext(String xmlPath){try {//将spring-context.xml中配置的bean对应的类的对象默认全部创建好SAXReader reader = new SAXReader();InputStream ins = ClassPathXmlApplicationContext.class.getClassLoader().getResourceAsStream(xmlPath);Document doc = reader.read(ins);//读取xml的根标签Element rootElement = doc.getRootElement();//拿到beans根标签下的所有bean子标签List<Element> childEleList = rootElement.elements();for(Element temp : childEleList){//读取某个bean标签的id、name、class的属性值String id = temp.attributeValue("id");String name = temp.attributeValue("name");String cls = temp.attributeValue("class");Object obj = Class.forName(cls).newInstance();//以id做key,拿到class的全路径创建对象作为value//将键值对存储到objMap中objMap.put(id,obj);//拿到name以,切割   以切割多个字符串做key,拿到class的全路径创建对象作为valueString[] nameAtt = name.split(",");for(String strName: nameAtt){objMap.put(strName,obj);}}} catch (Exception e) {e.printStackTrace();}}/*** 获取spring容器创建好的对象* @param name* @return*/@Overridepublic Object getBean(String name) {return objMap.get(name);}/*** 获取spring容器创建好的对象* @param name* @return*/@Overridepublic <T> T getBean(String name, Class<T> c) {return (T)objMap.get(name);}}

1.3.4 程序相关类
1.3.4.1 test

package com.powernode.test;import com.powernode.domain.Dog;import com.powernode.domain.User;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SelfSpringTest {public static void main(String[] args) {//启动spring容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");User u1 = context.getBean("u1", User.class);u1.sleep();}}

2.Spring的介绍

2.1 简介

Spring框架是由于软件开发的复杂性而创建的,初衷是为了让软件开发更加简单。Spring使用的是简单的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

Web Service,有2个显著特点:

1.数据格式是xml格式。

2.配置繁琐,“笨重”,对象关联性大,需在配置文件中各种配置。

基于这些原因,Spring框架提出了:IOC/DI(控制反转/依赖注入),AOP(面向切面编程)。

Spring框架可在任何类型的部署平台上为基于Java的现代企业应用程序提供全面的编程和配置模型。Spring的关键元素是在应用程序级别的基础架构支持:Spring专注于企业应用程序的“管道”,以便团队可以专注于应用程序级别的业务逻辑,而不必与特定的部署环境建立不必要的联系。

2.2 Spring的核心组件

在这里插入图片描述

2.2.1 核心容器
核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

l spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

l spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

l context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。spring-context-support 提供了对第三方库集成到 Spring 上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

l spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。

依赖关系图如下:
在这里插入图片描述

2.2.2 数据访问/集成
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

l JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。

l ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。

l OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。

l JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。

l 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)

2.2.3 Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:

l Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。

l Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。

l Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

l Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

2.2.4 其他
还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:

l AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

l Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

l Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

l Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

l 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

3.Spring的IOC的使用 IOC、DI

IOC:控制反转。将对象的创建、初始化、销毁等一系列的生命周期过程交给spring管理。

结婚:

方式1: 自己找女生--------------->吃饭、逛街、看电影、送回家等--------->结婚

(同学、同事、公交地铁1个月-3个月) 半年-1年半 1天

方式2: 媒婆(1个月)------------------------>结婚(1天)

吃饭:

方式1: 买菜、买米(30min-1h)---->蒸饭、洗菜、切菜、炒菜(1个小时)—>吃(15-30min)

方式2: 定外卖----------------->吃(15-30min)

面向过程----->面向对象----->面向接口----->面向组件(面向切面)–>面向服务—>面向百度

3.1 基本使用

3.1.1 创建项目并导入spring IoC相关jar包
在这里插入图片描述

在pom文件中,引入Spring的IoC核心jar包

<!--依赖-->
<dependencies><!--引入spring的context依赖,可以传递出aop beans core expression--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.4</version></dependency>
</dependencies>

3.1.2 创建User类

package com.bjpowernode.domain;import java.util.Date;/*** Created on 2021/7/16** @author 雷哥*/
public class User {private Integer id;private String name;private Integer age;private String address;private Date birth;public User() {}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +", birth=" + birth +'}';}
}

3.1.3 创建Spring的核心配置文件spring-context.xml/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"><!-- spring 核心配置文件 配置IOC容器中需要创建的bean --><bean id="userId"  name="user" class="com.bjpowernode.domain.User" />
</beans>

3.1.4 编写测试程序

public class Test {public static void main(String[] args) {//根据 spring的配置文件 创建 应用容器ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");System.out.println("马上获取bean");//从容器中获取 对象User user = (User) context.getBean("user");System.out.println(user);}
}

3.2 Bean标签属性介绍

3.2.1 id
是 bean的唯一标识 一个bean,其id 值只能有一个 。整个IOC 容器id 值不允许重复,使用名称作为key。

3.2.2 name
一个bean的名称,可以存在多个,多个之间使用逗号分隔。不论bean有没有定义name属性,默认id都会当做name。

3.2.3 class
bean的具体的类型,包名和类名组成。

3.2.4 scope
bean的作用域:如果不写scope,则默认为单例

prototype :非单例,每次获取都会创建一个新的bean对象。

singleton : 单例,多次获取永远同一个bean, 默认值。

request : 一次请求,基于web项目的bean的作用域。

session : 一次会话,基于web项目的bean的作用域。

3.2.5 lazy-init
延迟初始化(懒加载),默认只要加载了配置文件。bean对象就会被初始化,lazy-init则是获取时才会初始化。只针对单例模式有效,非单例每次获取都会创建,没有延迟初始化的意义

3.2.6 depends-on
初始化时依赖的对象,当前对象初始化前需先初始化depends-on指定的对象

3.2.7 init-method
对象初始化后,调用的方法

3.2.8 destroy-method
对象销毁时,调用的方法

3.2.9 autowire
属性自动装配

byName 根据属性名称装配

byType 根据类型装配

3.2.10 autowire-candidate
是否允许作为自动装配的候选项

true 作为自动装配的候选项

false 不作为自动装配的候选项

3.2.11 primary
优先使用该bean,因为Spring需要支持使用类型查找对象,在一个大类型下,可能存在多个小类型。如果根据大类型装配属性时,不知道使用哪个具体的对象,则可以根据primary设置优先级。

3.2.12 代码示例

<?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"><!-- spring 核心配置文件 配置IOC容器中需要创建的bean --><!-- <bean id="userId"  name="user" class="com.bjpowernode.domain.User"  />--><!--id : bean的唯一标识  整个IOC容器不能重复。name : bean的key,多个name之间使用逗号,class : 具体的bean的全路径scope : bean的作用域singleton 单例  默认prototype 非单例lazy-init="true" 获取时创建对象depends-on="test" 默认自上而下创建  depends-on 会优先创建 depends-on 对应的beaninit-method : 对象创建后调用的方法destroy-method :对象销毁时调用的方法, 容器调用closeautowire : 属性自动装配byName 根据属性名装配byType 根据属性类型装配primary :  当存在多个同样的类型时, primary 为true 则优先使用该bean--><bean id="userId2" name="user1,user2" class="com.bjpowernode.domain.User" scope="singleton" depends-on="test" init-method="init" destroy-method="destory" primary="true"  /><!--  test类 --><bean name="test" class="com.bjpowernode.domain.Test" /><bean name="userService1" class="com.bjpowernode.service.impl.UserServiceImpl1" primary="true" /><bean name="userService2" class="com.bjpowernode.service.impl.UserServiceImpl2" />
</beans>package com.bjpowernode.service;public interface IUserService {
}package com.bjpowernode.service.impl;import com.bjpowernode.service.IUserService;/*** @Description: 接口实现类1* @author: Mr.T* @date 2020-09-26 14:33*/
public class UserServiceImpl1 implements IUserService {
}package com.bjpowernode.service.impl;import com.bjpowernode.service.IUserService;
public class UserServiceImpl2 implements IUserService {
}package com.bjpowernode.domain;
public class User {private Integer id;private String name;public User(){System.out.println("构造方法执行  user 对象进行创建");}public  void sleep(){System.out.println("早睡早起!!!");}public void init(){System.out.println("对象初始化后调用的方法");}public  void  destory(){System.out.println("对象销毁时调用");}
}package com.bjpowernode.test;import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {//根据 spring的配置文件 创建 应用容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");System.out.println("马上获取bean");//从容器中获取 对象// 装备对象 : XX   XXX1  XX2   xx3User user = (User) context.getBean("user2");//System.out.println("21:"+user);System.out.println("22:"+context.getBean("user2"));//获取接口的类型System.out.println(context.getBean(IUserService.class));context.close();//关闭容器  此时会调用销毁的方法}
}

3.3 Bean对象创建的4种方式

3.3.1 构造方法创建
使用构造方法创建bean对象,是spring默认的创建方式。

<!-- 使用构造方法创建对象 -->
<bean id="user" class="com.bjpowernode.domian.User" />

3.3.2 静态工厂创建

<!-- 使用静态工厂创建对象 -->
<!--id : bean 的唯一标识class : 工厂类factory-method : 工厂方法-->
<bean id="user2" class="com.bjpowernode.factory.UserStaticFactory" factory-method="getObj" />package com.bjpowernode.factory;import com.bjpowernode.domian.User;public class UserStaticFactory {/*** 静态工厂中用于创建对象的方法* @return*/public static User getObj(){System.out.println("静态工厂中 创建对象的方法 执行了");return  new User();}
}

3.3.3 非静态工厂创建

<!--非静态工厂创建对象在非静态工厂中,创建对象的方法是非静态方法。非静态方法的执行,首先需要该类对象注意: 使用非静态工厂创建对象,首先需要创建工厂类对象
-->
<!-- 工厂类对象 -->
<bean id="userFactory" class="com.bjpowernode.factory.UserFactory" />
<!-- 使用非静态工厂创建对象 -->
<!--factory-bean : 非静态工厂对象factory-method : 创建对象的非静态方法
-->
<bean id="user3" factory-bean="userFactory" factory-method="getObj" />package com.bjpowernode.factory;import com.bjpowernode.domian.User;public class UserFactory {/*** 工厂中用于创建对象的方法* @return*/public  User getObj(){System.out.println("非静态工厂中创建对象的方法 执行了");return  new User();}
}

3.3.4 注解创建
Spring为简化对象的创建方式,提供了注解。

3.3.4.1 组件注解:
3.3.4.1.1 @Component(“bs”)
表示该类为一个被Spring管理的组件。但是,由于在开发中为了让代码的可读性更高。

Spring基于分层思想,将需要创建的组件分为以下几类:

3.3.4.1.2 @Controller
@Controller注解,标识该类是controller层的类。并且,注意在使用SpringMVC时,所有的Constroller,必须使用@Controller注解。

3.3.4.1.3 @Service
@Service注解,标识该类是业务层的类。

3.3.4.1.4 @Respository
@Respository注解,标识该类是操作数据层的类。

注意:

以上注解是Spring中定义的创建对象的注解,都可以创建对象,如果该类有明确的作用,有自己所属的层,则建议使用相应的注解,如果实在无法区分该类所属层,可以使用@Component注解。

3.3.4.2 注解使用步骤
3.3.4.2.1 开启组件扫描
在spring的核心配置文件中,开启注解扫描,让Spring将被注解修饰的类,创建对相关。

xml头部

xmlns:context=“http://www.springframework.org/schema/context”

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

<!--开启组件扫描-->
<context:component-scan base-package="com.bjpowernode.*" />

3.3.4.2.2 添加注解

package com.bjpowernode.domian;import org.springframework.stereotype.Component;
@Component
public class Person {public Person(){System.out.println("Person的构造方法.........");}
}

3.3.5 什么时候使用XML配置和注解
能使用注解时,就使用了注解,注解非常方便。但是,在第三方的类中,是无法使用注解的。因为无法在别人提供的源码上加上Spring注解,此时只能使用XML配置的形式,配置第三方类的Bean信息。

3.4 IOC属性注入的3种方式

为对象属性设置值,就是属性注入。

3.4.1 构造方法属性注入:DI(依赖注入,给对象的属性赋值)

<?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 class="com.bjpowernode.domain.User" /><!--有参数的构造方法此时是2个参数的构造方法index : 参数下标  从 0开始value : 属性的值--><bean id="user2" class="com.bjpowernode.domain.User" ><constructor-arg index="0" value="1001" /><constructor-arg index="1" value="韩梅梅" /></bean><!-- 有参数的构造方法使用index下标查找 属性 存在问题 都只有一个参数 则默认使用后面的构造方法可以使用 type 指定参数的类型更推荐 使用name属性 : name表示构造器中参数的名称--><bean id="user3" class="com.bjpowernode.domain.User"><constructor-arg index="0" value="1001" type="java.lang.Integer"  /></bean><bean id="user4" class="com.bjpowernode.domain.User"><constructor-arg name="name" value="韩梅梅" /></bean>
</beans>package com.bjpowernode.domain;public class User {/***  id 属性*/private Integer id;/***  name 属性*/private String name;public User(){System.out.println("无参数构造方法");}public User(Integer id) {System.out.println("id参数方法");this.id = id;}public User(String name) {System.out.println("name参数构造方法");this.name = name;}public User(Integer id, String name) {System.out.println("id,name参数构造方法");this.id = id;this.name = name;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

3.4.2 set方法属性注入

<?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"><!--使用set方法进行属性注入property 表示属性name : 表示属性对应的set方法名,去掉set前缀,首字母小写。并不是真正的属性名--><bean id="dg" class="com.powernode.pojo.Dog"><property name="sonList"><list><value>小黑</value><value>小白</value><value>小花</value></list></property><property name="wifeList"><set><value>小翠儿</value><value>如花</value></set></property><property name="friendMap"><map><entry key="uName1" value="土狗"></entry><entry key="uName2" value="泰迪"></entry><entry key="uName3" value-ref="u1"></entry></map></property><property name="props"><props><prop key="strain">土狗</prop><prop key="age">15</prop><prop key="gender"></prop></props></property>
</bean></beans>

3.4.3 注解属性注入
在spring中,为了简化属性的注入,Spring提供注解:@Autowired,Spring会自动从IOC容器中,为这个属性查找相应类型的值,进行注入。

  1. 开启包的注解扫描
    <context:component-scan base-package=“com.*” />

  2. 使用注解

package com.bjpowernode.domain;import org.springframework.beans.factory.annotation.Autowired;import java.util.Date;
public class Student {public Integer id;public String name;@Autowired  //使用注解自动注入//User 对象public User user;public void setStudentId(Integer id) {System.out.println("set方法被调用了............");this.id = id;}/*   public void setUser(User user) {this.user = user;}*/
}

注意:

在使用自动注入时,可以在bean标签上,配置autowire,但是此时必须有该属性的set方法,@Autowired注解,是不需要set方法的。

如果是在xml中注入对象,值使用ref属性。value属性,只支持boolean,数字,字符串等。

3.5 常见类型的属性注入

在Spring中,提供了丰富的标签,进行各种属性的注入。常见的类型:

数字、字符串、boolean、数组、set、list、map、properties。

package com.bjpowernode.domain;import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;public class Person {private Integer id;private String name;private boolean sex;// true  男 false 女private String[] likes;//爱好private Set<String> girlFriends; //女朋友private List<Dream> dreams;//梦想private Map<String,String> house; //房子private Properties properties; //配置文件属性public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public boolean getSex() {return sex;}public void setSex(boolean sex) {this.sex = sex;}public String[] getLikes() {return likes;}public void setLikes(String[] likes) {this.likes = likes;}public Set<String> getGirlFriends() {return girlFriends;}public void setGirlFriends(Set<String> girlFriends) {this.girlFriends = girlFriends;}public List<Dream> getDreams() {return dreams;}public void setDreams(List<Dream> dreams) {this.dreams = dreams;}public Map<String, String> getHouse() {return house;}public void setHouse(Map<String, String> house) {this.house = house;}public Properties getProperties() {return properties;}public void setProperties(Properties properties) {this.properties = properties;}
}package com.bjpowernode.domain;public class Dream {private String title;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}
}<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 简单的属性注入 : 基本数据类型 + string --><bean id="person1" class="com.bjpowernode.domain.Person" ><!-- Integer 类型的属性注入 --><property name="id" value="1001" /><!-- String 类型的属性注入 --><property name="name" value="佚名" /><!-- boolean 属性注入 --><property name="sex"  value="true" /></bean><!-- 数组类型 --><bean id="person2" class="com.bjpowernode.domain.Person" ><property name="likes" ><array><value>足球</value><value>篮球</value><value>羽毛球</value></array></property></bean><!--  set 类型注入 --><bean id="person3" class="com.bjpowernode.domain.Person" ><property name="girlFriends" ><set><value>韩梅梅</value><value>Lucy</value><value>Lucy</value><value>Rose</value></set></property></bean><bean id="dream1" class="com.bjpowernode.domain.Dream"><property name="title" value="数钱数到手抽筋" /></bean><!-- list 类型 --><bean id="person4" class="com.bjpowernode.domain.Person" ><property name="dreams" ><list><bean class="com.bjpowernode.domain.Dream"><property name="title" value="解放全人类" /></bean><bean class="com.bjpowernode.domain.Dream"><property name="title" value="世界和平" /></bean><ref bean="dream1"/></list></property></bean><!-- map结构   --><bean id="person5" class="com.bjpowernode.domain.Person" ><property name="house" ><map><entry key="wh" value="江滩" /><entry key="bj" value="后海" /><entry key="hz" value="西湖" /></map></property></bean><!-- properties  --><bean id="person6" class="com.bjpowernode.domain.Person" ><property name="properties" ><props><prop key="driver">驱动</prop><prop key="url">url</prop></props></property></bean>
</beans>package com.bjpowernode.test;import com.bjpowernode.domain.Dream;
import com.bjpowernode.domain.Person;
import com.bjpowernode.domain.Student;
import com.bjpowernode.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.Arrays;
import java.util.List;
import java.util.Properties;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");Person person1 = (Person) context.getBean("person1");System.out.println(person1.getId() +"  "+ person1.getName() + " "+ person1.getSex() );Person person2 = (Person) context.getBean("person2");String[] likes = person2.getLikes();System.out.println(Arrays.asList(likes));Person person3= (Person) context.getBean("person3");System.out.println(person3.getGirlFriends());Person person4 = (Person) context.getBean("person4");List<Dream> dreams = person4.getDreams();System.out.println(dreams.get(0).getTitle());System.out.println(dreams.get(1).getTitle());System.out.println(dreams.get(2).getTitle());Person person5 = (Person) context.getBean("person5");System.out.println(person5.getHouse());Person person6 = (Person) context.getBean("person6");Properties properties = person6.getProperties();System.out.println(properties.getProperty("driver"));System.out.println(properties.getProperty("url"));}
}

3.6 使用IOC容器,改造传统项目

3.6.1 xml配置版
3.6.1.1 创建项目并加入依赖
在这里插入图片描述

<!--依赖-->
<dependencies><!--引入spring的context依赖,可以传递出aop beans core expression--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.4</version></dependency>
</dependencies>

3.6.1.2 项目结构
在这里插入图片描述

3.6.1.3 配置文件

<?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"><!-- 声明  com.bjpowernode.dao 对象 --><bean id="userDao" class="com.bjpowernode.dao.UserDao" /><!-- 声明service 对象 --><bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType"><!-- 使用自动装配 则不需要 声明属性注入 但是要有set方法 --><!--<property name="userDao" ref="userDao" />--></bean><!-- 声明controller --><bean id="userController" class="com.bjpowernode.controller.UserController" autowire="byType"><!-- 使用自动装配 则不需要 声明属性注入 但是要有set方法--><!--<property name="userService" ref="userService"/>--></bean>
</beans>

3.6.1.4 controller

package com.bjpowernode.controller;import com.bjpowernode.service.IUserService;public class UserController {private IUserService userService;public void register(){System.out.println("控制层的   register  方法");userService.register();}public void setUserService(IUserService userService) {this.userService = userService;}
}

3.6.1.5 dao

package com.bjpowernode.dao;
public class UserDao {public void add(){System.out.println("进行数据库数据新增操作");}
}

3.6.1.6 service

package com.bjpowernode.service;public interface IUserService {/*** 注册接口*/public void register();
}package com.bjpowernode.service.impl;import com.bjpowernode.dao.UserDao;
import com.bjpowernode.service.IUserService;public class UserServiceImpl implements IUserService {/*** com.bjpowernode.dao 层 属性*/private UserDao userDao;@Overridepublic void register() {System.out.println("com.bjpowernode.service 的 register ");userDao.add();}/***  使用set方法 是为了自动装配 或者进行set 属性设置* @param userDao*/public void setUserDao(UserDao userDao) {this.userDao = userDao;}
}

3.6.1.7 test

package com.bjpowernode;
import com.bjpowernode.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");UserController bean = context.getBean(UserController.class);bean.register();}
}

3.6.2 注解版
3.6.2.1 配置文件

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 开启组件扫描 --><context:component-scan base-package="com.*" />
</beans>

3.6.2.2 controller

package com.bjpowernode.controller;import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;@Controller
public class UserController {@Autowiredprivate IUserService userService;public void register(){System.out.println("控制层的   register  方法");userService.register();}
}

3.6.2.3 dao

package com.bjpowernode.dao;import org.springframework.stereotype.Repository;@Repository
public class UserDao {public void add(){System.out.println("进行数据库数据新增操作");}
}

3.6.2.4 service

package com.bjpowernode.service;public interface IUserService {/*** 注册接口*/public void register();
}package com.bjpowernode.service.impl;import com.bjpowernode.dao.UserDao;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements IUserService {/*** com.bjpowernode.dao 层 属性*/@Autowiredprivate UserDao userDao;@Overridepublic void register() {System.out.println("com.bjpowernode.service 的 register ");userDao.add();}
}

3.6.2.5 test

package com.bjpowernode.test;import com.bjpowernode.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");//UserController bean = context.getBean(UserController.class);//bean.register();//程序员自己创建的对象  不在IOC 自己容器中//new UserController().register();}
}

4.AOP

com.powernode.aadenglu

Login: login():登录方法

com.powernode.anquan

Security: isSecurity():检测操作环境是否安全

com.powernode.bmapper

CBCBankMapper(核心类): selectMoney() updateMoney() updateInvest() update2Tel()

com.powernode.crizhi

Logger: log():记录用户操作细节

com.powernode.dqinli

Clean :cleanResource():清理缓存

Expt: handExpt()

4.1 AOP简介:面向切面(面向组件)

DefaultAopProxyFactory

代理

静态代理

静态代理,每个被代理类都需要创建对应的代理类。随着程序的扩展,代理类也会增多,臃肿,维护量变多,为了解决这个问题,Java中,提供了动态代理技术,开发者不需要自己定义代理类,代理类由JDK动态的创建,开发只需要指定被代理的类即可。

切面(aspect):除了核心类以外的其他类称之为切面

通知(advisor):切面中的方法称之为通知

核心类:一个项目中不能省略的模块类

核心方法:核心类中的方法称之为核心方法

连接点:核心类中的某一个方法

切入点(pointcut):某个包下的某个类下的某一批方法

代理(proxy):将多个切面与核心类组合在一起,形成一个新的类,这个类称之为代理类

织入(weaver):书写代理类的过程称之为织入

4.2 动态代理

4.2.1 JDK动态代理
4.2.1.1 Proxy
该类提供了方法创建代理类和代理类的对象的方法

创建一个代理类并返回代理类对象

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

loader : 类加载器,指定类加载器,是为了精确的定位类

interfaces : 接口Class类,使用JDK的反射,必须要有接口

h :InvocationHandler ,代理的处理器,每个代理类都有一个关联的处理器

4.2.1.2 InvocationHandler
是每个代理类对应的处理器

Object 方法调用的返回值,可以作为被代理的方法调用的返回值

proxy : 代理类对象

method : 目标类中被代理的方法

args : 目标类中被代理的方法的运行参数

Object invoke(Object proxy,Method method,Object[] args)

4.2.1.3 代码示例
4.2.1.3.1 目标类接口

package com.bjpowernode.proxy.demo02;/*** @Description: 目标类接口* @author: Mr.T* @date 2020-09-27 10:38*/
public interface ITargetClass {/*** 房子出租* @param m*/void rent(int m);
}

4.2.1.3.2 目标类

package com.bjpowernode.proxy.demo02;/*** @Description: 目标类* @author: Mr.T* @date 2020-09-27 10:39*/
public class TargetClass implements ITargetClass {@Overridepublic void rent(int m) {System.out.println("出租的金额为:" + m);}
}

4.2.1.3.3 代理类处理器

package com.bjpowernode.proxy.demo02;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** @Description: 代理的处理器*              处理器会被绑定一个代理*              帮助代理调用目标方法* @author: Mr.T* @date 2020-09-27 10:40*/
public class ProxyHanlder implements InvocationHandler {/***  目标方法类的对象*/private Object targetObj;public ProxyHanlder(Object targetObj){this.targetObj = targetObj;}/**** @param proxy  生成的代理类的对象* @param method  目标类中被代理的方法* @param args    目标类中被代理的方法实际参数* @return      可以当做目标方法的返回值* @throws Throwable*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//使用反射调用 目标类中的方法Object obj = method.invoke(targetObj, args);return obj;}
}

4.2.1.3.4 测试类

package com.bjpowernode.proxy.demo02;import java.lang.reflect.Proxy;/*** @Description: TODO* @author: Mr.T* @date 2020-09-27 10:45*/
public class Test {public static void main(String[] args) {System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//创建了目标类对象ITargetClass targetClass = new TargetClass();//创建处理器ProxyHanlder proxyHanlder = new ProxyHanlder(targetClass);//创建具体的代理类和对象 具体产生的代理类  会实现 接口 所以能够转化为 接口类型ITargetClass proxy = (ITargetClass) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{ITargetClass.class}, proxyHanlder);// 调用代理类中  rent方法 $proxy0proxy.rent(100);}
}

4.2.1.3.5 生成代理类源码

package com.bjpowernode.proxy.demo02;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.UndeclaredThrowableException;/*** @Description: 动态代理生成的代理类*      Proxy : JDK中所有生成的代理的父类*      ITargetClass : 指定被代理类的接口** @author: Mr.T* @date 2020-09-27 10:59*/
public final class $Proxy0 extends Proxy implements ITargetClass
{private static Method m0; //hashCode 方法private static Method m1; // equalsprivate static Method m2; //toStringprivate static Method m3; // rent 方法  被代理的方法static {try {$Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);$Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));$Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);$Proxy0.m3 = Class.forName("com.bjpowernode.proxy.demo02.ITargetClass").getMethod("rent", Integer.TYPE);}catch (NoSuchMethodException ex) {throw new NoSuchMethodError(ex.getMessage());}catch (ClassNotFoundException ex2) {throw new NoClassDefFoundError(ex2.getMessage());}}/***  invocationHandler 就是定义的 invocationHandler* @param invocationHandler*/public $Proxy0(final InvocationHandler invocationHandler) {super(invocationHandler); //Proxy(InvocationHandler invocationHandler) --> 为父类中 InvocationHandler 赋值//当前类中 InvocationHandler 对象  且有值/*Proxy(InvocationHandler h) {Objects.requireNonNull(h);this.h = h;}* */}public final boolean equals(final Object o) {try {return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });}catch (Error | RuntimeException error) {throw;}catch (Throwable t) {throw new UndeclaredThrowableException(t);}}public final String toString() {try {return (String)super.h.invoke(this, $Proxy0.m2, null);}catch (Error | RuntimeException error) {throw;}catch (Throwable t) {throw new UndeclaredThrowableException(t);}}public final void rent(final int n) {try {//super.h   this.h   ---> 自定义的  ProxyHanlder//调用自定义的ProxyHanlder 中的invoke方法   : $Proxy0 对象//$Proxy0.m3  rent 方法//new Object[] { n } 传入的参数super.h.invoke(this, $Proxy0.m3, new Object[] { n });}catch (Error | RuntimeException error) {throw;}catch (Throwable t) {throw new UndeclaredThrowableException(t);}}public final int hashCode() {try {return (int)super.h.invoke(this, $Proxy0.m0, null);}catch (Error | RuntimeException error) {throw;}catch (Throwable t) {throw new UndeclaredThrowableException(t);}}
}

4.2.1.3.6 JDK动态代理的不足
在JDK中使用动态代理,必须有类的接口。因为生成的代理需要实现这个接口,这样我们生成的代理类对象,才能转化为代理目标的接口对象,然后根据接口中的方法,调用处理器中invoke方法。
在这里插入图片描述

4.2.2 Cglib动态代理
为了弥补JDK动态代理的不足,第三方组织封装一套工具包,cglib的工具包,这套包不基于接口,基于父子继承,通过重写的形式扩展方法,但是这个子类工具自动生成的。

早期,Cglib动态代理,性能相于JDK的动态代理高一些。JDK进行一些列优化,目前Spring默认使用的动态代理JDK,也支持Cglib。

4.2.2.1 Cglib动态代理的使用
4.2.2.1.1 MethodInterceptor
cglib中,提供的对方法执行拦截的接口。其中intercept是对具体方法进行拦截处理的方法。

public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,

                           MethodProxy proxy)

Object : 方法执行返回的结果

obj :增强类的对象

method :目标方法

proxy :用于回调的方法的对象

4.2.2.1.2 代码示例
4.2.2.1.2.1 导入jar包

<!-- 引入cglib 的jar 包-->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
</dependency>

4.2.2.1.2.2 创建被代理目标类

package com.bjpowernode.proxy.demo03;/*** @Description: 被代理的目标类* @author: Mr.T* @date 2020-09-27 14:13*/
public class TargetClass {public  void rent(){System.out.println("目标类中的出租方法");}
}

4.2.2.1.2.3 方法拦截器

package com.bjpowernode.proxy.demo03;import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/*** @Description: 方法执行的拦截器* @author: Mr.T* @date 2020-09-27 14:20*/
public class MyMethodInteceptor implements MethodInterceptor {/***  进行具体的拦截的方法* @param obj     被代理类的对象* @param method  被代理的目标方法* @param args  实际运行的参数* @param proxy 代理类对象* @return* @throws Throwable*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("前置增强");//代理 调用父类中的方法Object o = proxy.invokeSuper(obj, args);System.out.println("intercept  执行了");//执行了System.out.println("后置增强");return o ;}
}

4.2.2.1.2.4 测试类

package com.bjpowernode.proxy.demo03;import net.sf.cglib.proxy.Enhancer;/*** @Description: TODO* @author: Mr.T* @date 2020-09-27 14:21*/
public class Test {public static void main(String[] args) {//增强类工具  可以创建代理类对象Enhancer enhancer = new Enhancer();enhancer.setSuperclass(TargetClass.class);//设置调用时 回调enhancer.setCallback(new MyMethodInteceptor());//创建代理类对象TargetClass proxy = (TargetClass) enhancer.create();proxy.rent();}
}

4.2.2.2 动态代理的不足
不论是JDK的动态代理,还是第三方cglib动态代理,都需要开发者编写代码处理程序。程序结构基本上大同小异,重复造轮子。基于这样的情况,在Spring中,提供了2种方式:xml配置形式和注解形式,使用动态代理。这种模式就是Spring Aop技术。其底层依然是动态代理。

4.3 Spring的AOP配置

在Spring中,AOP的配置主要分为2类:xml配置和注解配置

XML配置也分为两种,一种Spring的原生支持,一种是Spring的aspects这个相关的框架。

4.3.1 AOP的相关概念
连接点(JoinPoint):所谓连接点是指那些被拦截的点,而spring中这些点就是指方法,因为spring只支持方法类型的连接点。

切入点(PointCut):所谓切入点就是指我们要对那些JoinPoint进行拦截的定义,指的是具体的拦截的位置

增强/通知(Advice) : 增强就是对具体的连接点进行扩展的功能。由于一般对方法进行增强,分为在方法前执行或者方法后,或者发生异常执行等等,所以增强被分为:前置增强(前置通知)、后置增强(后置通知)、环绕通知(环绕增强)、异常增强(异常通知)

引介(Introduction):引介是一种特殊的Advice,在不修改代码的前提下,引介可以在运行期为类动态的添加一些方法或Field.

目标(Target) :被代理的类(需要增强类)

织入(Weaving) :把Advice应用到Target的过程

代理(Proxy):使用AOP配置后产生的代理类

切面(Aspect):切点和增强整合形成了切面
在这里插入图片描述

4.3.2 Spring自身AOP具体配置
4.3.2.1 引入aop相关jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>02-spring-aop01</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.2.0.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency></dependencies></project>

4.3.2.2 定义增强类
4.3.2.2.1 前置增强-MethodBeforeAdvice

package com.bjpowernode.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;/*** @Description: spring 规定的增强方法接口* @author: Mr.T* @date 2020-09-27 15:42*/
public class MyBeforeAdvice implements MethodBeforeAdvice {/**** @param method  目标方法* @param args   实际运行的参数* @param target  目标类对象* @throws Throwable*/@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("前置增强的方法");}
}

4.3.2.2.2 后置增强-AfterReturningAdvice

package com.bjpowernode.advice;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;/*** @Description: 后置增强接口* @author: Mr.T* @date 2020-09-27 15:55*/
public class MyAfterAdvice implements AfterReturningAdvice {/**** @param returnValue 被增强的方法运行后返回的数据* @param method     被增强的方法* @param args      方法运行的参数* @param target       目标类对象* @throws Throwable*/@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("后置增强方法");}
}

4.3.2.2.3 环绕增强-MethodInterceptor

package com.bjpowernode.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;/*** @Description: 环绕增强* @author: Mr.T* @date 2020-09-27 16:04*/
public class MyAroundAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("前置增强");Object rs = invocation.proceed();//调用 目标方法System.out.println("后置增强");return rs;}
}

4.3.2.2.4 异常增强-ThrowsAdvice
异常增强中的增强方法必须叫:afterThrowing,并且必须定义参数接收发生的异常信息。

package com.bjpowernode.advice;import org.springframework.aop.ThrowsAdvice;/*** @Description: 异常增强类* @author: Mr.T* @date 2020-09-27 16:12*/
public class MyExceptionAdvice implements ThrowsAdvice {public void afterThrowing(Exception ex){System.out.println("异常增强的方法!!!!!!");}
}

4.3.2.3 目标类

package com.bjpowernode;public interface ITargetClass {/*** 待增强的目标方法*/void targetMethod();/*** 待增强的方法* @param msg* @return*/String afterTargetMethod(String msg);/*** 环绕增强的方法*/void aroundTargetMethod();/***  执行会发生异常*/void runException();
}package com.bjpowernode.impl;import com.bjpowernode.ITargetClass;/*** @Description: 目标类* @author: Mr.T* @date 2020-09-27 15:38*/
public class TargetClassImpl implements ITargetClass {@Overridepublic void targetMethod() {System.out.println("待增强的目标方法");}@Overridepublic String afterTargetMethod(String msg) {System.out.println("待增强的目标方法 --- afterTargetMethod");return "被增强的方法的返回值";}public void aroundTargetMethod() {System.out.println("待增强的目标方法 --- aroundTargetMethod");}/*** 发生异常*/public void runException() {System.out.println("待增强的目标方法 --- runException");int m = 0;int n = 100/m;}}

4.3.2.4 aop配置

<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 定义目标类对象 --><bean id="targetClass" class="com.bjpowernode.impl.TargetClassImpl" /><!-- 定义增强类对象 前置增强类 --><bean id="myBeforeAdvice" class="com.bjpowernode.advice.MyBeforeAdvice" /><!-- 定义增强类对象  后置增强 --><bean id="myAfterAdvice" class="com.bjpowernode.advice.MyAfterAdvice" /><!-- 定义增强类 环绕增强 --><bean id="myAroundAdvice" class="com.bjpowernode.advice.MyAroundAdvice" /><!-- 定义增强类  异常增强类 --><bean id="myExceptionAdvice" class="com.bjpowernode.advice.MyExceptionAdvice" /><!-- 进行织入 --><aop:config><!--id : 连接点的唯一标识expression : 连接点的表达式execution(* 包名.类名.方法名(..))* 指任意字符.. 表示参数可以是任意个--><aop:pointcut id="beforePoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.targetMethod(..))"/><!-- 后置增强的切点 --><aop:pointcut id="afterPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.afterTargetMethod(..))"/><!-- 环绕增强的切点 --><aop:pointcut id="aroundPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.aroundTargetMethod(..))"/><!-- 异常增强的切点 --><aop:pointcut id="exceptionPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.runException(..))"/><!--织入将增强和连接点 结合--><aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="beforePoint" /><!-- 织入后置增强的织入--><aop:advisor advice-ref="myAfterAdvice" pointcut-ref="afterPoint" /><!--织入环绕增强的织入--><aop:advisor advice-ref="myAroundAdvice"  pointcut-ref="aroundPoint" /><!--织入异常增强的织入--><aop:advisor advice-ref="myExceptionAdvice"  pointcut-ref="exceptionPoint" /></aop:config></beans>

4.3.2.5 测试类

package com.bjpowernode;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");ITargetClass targetClass = context.getBean(ITargetClass.class);targetClass.runException();}
}

4.3.3 AspectJ框架AOP配置
在原生的spring中,每种增强都需要单独定义一个类实现相应的接口。增强类本身就更庞大,而且方法的名称是固定的。基于这种情况,AspectJ提供了相对更加灵活的方式。

在AspectJ中,只需要定义一个增强类即可,并且方法的名称可以任意定义。

4.3.3.1 引入相关jar

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>02-spring-aop02</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.2.0.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency></dependencies>
</project>

4.3.3.2 编写增强类

package com.bjpowernode.advice;import org.aopalliance.intercept.Invocation;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.ProceedingJoinPoint;public class MyAdvice {public void beforAdvice(){System.out.println("前置增强的方法");}public void afterAdvice(String name,String rs){System.out.println("后置增强的方法");}public void aroundAdvice(ProceedingJoinPoint joinPoint){System.out.println("前置增强");try {joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("后置增强");}/*** 异常增强* @param exception*/public  void exceptionAdvice(Exception exception){System.out.println("异常增强!");}
}

4.3.3.3 编写目标类

package com.bjpowernode;public interface ITargetClass {/*** 前置增强的方法*/void  beforeMethod();/*** 后置增强的方法*/String afterMethod(String name1);/*** 环绕增强的方法*/void aroundMethod();/*** 异常增的方法*/void runExceptionMethod();
}package com.bjpowernode.impl;import com.bjpowernode.ITargetClass;public class TargetClassImpl  implements ITargetClass {@Overridepublic void beforeMethod() {System.out.println("待前置增强--------beforeMethod");}@Overridepublic String afterMethod(String name) {System.out.println("待后置增强--------afterMethod");return  "韩梅梅";}@Overridepublic void aroundMethod() {System.out.println("待环绕增强--------aroundMethod");}@Overridepublic void runExceptionMethod() {System.out.println("待异常增强--------runExceptionMethod");int m = 0;int n = 100/m;}
}

4.3.3.4 配置AspectJ的增强配置

<?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: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/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 定义增强的目标类对象 --><bean id="targetClass" class="com.bjpowernode.impl.TargetClassImpl" /><!-- 定义增强类的对象 --><bean id="myAdvice" class="com.bjpowernode.advice.MyAdvice" /><!-- 进行AOP配置 --><aop:config><!-- 前置切点 --><!--aop:before : aspectJ中 前置增强的配置method : 当前增强类中前置增强的方法  方法名pointcut-ref : 增强连接点--><aop:pointcut id="beforPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.beforeMethod(..)) " /><!-- 后置切点 --><!-- args 配置被增强的方法的参数名称 --><aop:pointcut id="afterPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.afterMethod(..)) and args(name)"   /><!-- 环绕切点 --><aop:pointcut id="aroundPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.aroundMethod(..))"  /><!-- 异常切点 --><aop:pointcut id="exceptionPoint" expression="execution(* com.bjpowernode.impl.TargetClassImpl.runExceptionMethod(..))" /><aop:aspect ref="myAdvice"><!--  <aop:before method="beforAdvice" pointcut-ref="beforPoint" />--><!--arg-names :后置增强中增强的方法的参数名称注意: name 也是被增强的方法的参数名称 参数名称要一致returning :返回结果的参数名称--><aop:after-returning method="afterAdvice" pointcut-ref="afterPoint" arg-names="name,rs"   returning="rs" /><!--<aop:around method="aroundAdvice" pointcut-ref="aroundPoint"  />--><!--throwing : 接收异常参数的名称--><aop:after-throwing method="exceptionAdvice" pointcut-ref="exceptionPoint" throwing="exception"  /></aop:aspect></aop:config></beans>

4.3.3.5 进行测试

package com.bjpowernode;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");ITargetClass bean = context.getBean(ITargetClass.class);bean.runExceptionMethod();}
}

4.3.4 AspectJ的AOP注解方式
4.3.4.1 引入相关jar包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>02-spring-aop3</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><spring.version>5.2.0.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency></dependencies>
</project>

4.3.4.2 定义增强类

package com.bjpowernode.advice;import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAdvice {@Before(value = "execution(* com.bjpowernode.impl.TargetClassImpl.beforeMethod(..))")public void beforAdvice(){System.out.println("前置增强的方法");}/**args 被增强的方法的参数名称* argNames  增强方法的参数名称*  参数名称必须一致* returning 参数名称* */@AfterReturning(value="execution(* com.bjpowernode.impl.TargetClassImpl.afterMethod(..)) && args(name)",argNames = "name,rs" ,returning = "rs" )public void afterAdvice(String name,String rs){System.out.println("后置增强的方法");}@Around(value="execution(* com.bjpowernode.impl.TargetClassImpl.aroundMethod(..))")public void aroundAdvice(ProceedingJoinPoint joinPoint){System.out.println("前置增强");try {joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();}System.out.println("后置增强");}/*** 异常增强* @param exception*/@AfterThrowing(value="execution(* com.bjpowernode.impl.TargetClassImpl.runExceptionMethod(..))",throwing = "exception" )public  void exceptionAdvice(Exception exception){System.out.println("异常增强!");}
}

4.3.4.3 目标类

package com.bjpowernode;public interface ITargetClass {/*** 前置增强的方法*/void  beforeMethod();/*** 后置增强的方法*/String afterMethod(String name);/*** 环绕增强的方法*/void aroundMethod();/*** 异常增的方法*/void runExceptionMethod();
}package com.bjpowernode.impl;import com.bjpowernode.ITargetClass;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;@Component
public class TargetClassImpl  implements ITargetClass {@Overridepublic void beforeMethod() {System.out.println("待前置增强--------beforeMethod");}@Overridepublic String afterMethod(String name) {System.out.println("待后置增强--------afterMethod");return  "韩梅梅";}@Overridepublic void aroundMethod() {System.out.println("待环绕增强--------aroundMethod");}@Overridepublic void runExceptionMethod() {System.out.println("待异常增强--------runExceptionMethod");int m = 0;int n = 100/m;}
}

4.3.4.4 开启相关注解

<?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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 开启组件扫描 --><context:component-scan base-package="com.*" /><!-- 开启aspectj 的相关注解 --><aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

4.3.4.5 测试类

package com.bjpowernode;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");ITargetClass bean = context.getBean(ITargetClass.class);bean.runExceptionMethod();}
}

5.Spring整合Mybatis

Spring整合Mybatis就是将Mybatis交给Spring进行管理,将Mybatis的SqlSession对象,放入IOC容器中,并且可以利用自动装配功能,为每个数据库操作层,注入SqlSession。并且Spring内置可以有代理的,可以根据SqlSession对象及数据操作接口,创建Mapper接口的代理对象,此时Mapper的代理在IOC容器中,那么可以将Mapper接口的对象注入到Service中。

5.1 多XML版

使用配置文件版本,Mybatis配置文件和Spring配置文件是单独的。

5.1.1 引入相关jar包
5.1.1.1 spring相关jar包

<!-- spring相关jar包  开始 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.0.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>5.2.0.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.2.0.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.0.RELEASE</version>
</dependency>
<!-- spring相关jar包  结束 -->

5.1.1.2 mybatis相关jar包

<!-- mybatis核心包  开始-->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version>
</dependency>
<!-- mybatis核心包  结束-->

5.1.1.3 数据库相关jar包

<!-- mysql jdbc 数据库包 开始 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version>
</dependency>
<!-- mysql jdbc 数据库包 结束 -->

5.1.1.4 日志相关jar包

<!-- 日志相关jar包  开始 -->
<dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version>
</dependency>
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.13.3</version>
</dependency>
<!-- 日志相关jar包  结束 -->

5.1.1.5 spring和mybatis整合包

<!-- spring和 mybatis 整合包 开始   -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.4</version>
</dependency>
<!-- spring和 mybatis 整合包  结束-->

5.1.1.6 mybatis分页插件包

<!-- mybatis分页插件包   开始-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version>
</dependency>
<!-- mybatis分页插件包   结束-->

5.1.2 相关类

5.1.2.1 domain

package com.bjpowernode.domain;public class User {private Integer id;private  String username;private String password;private String realname;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getRealname() {return realname;}public void setRealname(String realname) {this.realname = realname;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", password='" + password + '\'' +", realname='" + realname + '\'' +'}';}
}

5.1.2.2 mapper

package com.bjpowernode.mapper;import com.bjpowernode.domain.User;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface UserMapper {/*** 根据ID 查询用户* @param id* @return*/User selectById(@Param("id") Integer id);/*** 查询所有* @return*/List<User> selectAll();
}

5.1.2.3 service

package com.bjpowernode.service;import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;public interface IUserService {User queryUser(Integer id);PageInfo<User> queryPage(Integer page,Integer limit);
}package com.bjpowernode.service.impl;import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;public class UserServiceImpl implements IUserService {private UserMapper  userMapper;@Overridepublic User queryUser(Integer id) {return userMapper.selectById(id);}@Overridepublic PageInfo<User> queryPage(Integer page,Integer limit) {Page<User> users = PageHelper.startPage(page, limit);userMapper.selectAll();return users.toPageInfo();}/*** 使用xml形式注入 mapper* @param userMapper*/public void setUserMapper(UserMapper userMapper) {this.userMapper = userMapper;}
}

5.1.2.4 测试类

package com.bjpowernode;import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import java.util.List;public class Test {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");IUserService bean = context.getBean(IUserService.class);PageInfo<User> pageInfo = bean.queryPage(2, 1);List<User> list = pageInfo.getList();for (User user : list) {System.out.println(user);}}
}

5.1.3 相关配置文件
5.1.3.1 jdbc配置文件
#数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&useSSL=false&characterEncoding=UTF8&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
5.1.3.2 日志配置文件

# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

5.1.3.3 mybatis核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 引入数据库配置文件 --><!--<properties resource="jdbc.properties" />--><!-- 全局设置 --><settings><setting name="logImpl" value="LOG4J"/></settings><!-- 配置类别名 --><typeAliases><package name="com.bjpowernode.domain"/></typeAliases><!-- 配置分页插件 --><plugins><plugin interceptor="com.github.pagehelper.PageInterceptor" /></plugins><!-- 数据源环境 -->
<!--    <environments default="dev"><environment id="dev"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments>--><!-- 映射文件 --><mappers><mapper resource="mapper/UserMapper.xml" /></mappers>
</configuration>

5.1.3.4 mybatis映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.mapper.UserMapper"><select id="selectById" resultType="com.bjpowernode.domain.User">select * from user where id = #{id}</select><select id="selectAll" resultType="com.bjpowernode.domain.User">select * from user</select>
</mapper>

5.1.3.5 spring核心配置文件

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--终极目标 为 每个service 注入一个Mapper 对象1. Mapper 对象2. SqlSession 获取3. SqlSession 要根据 SqlSessionFactory 获取4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器6. 配置数据源--><!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性--><context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" /><!--2. 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!--3. 配置SqlSessionFactoryBean 对象--><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><!--  mybatis 核心配置文件 --><property name="configLocation" value="mybatis.xml" /><property name="dataSource" ref="dataSource" /></bean><!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 --><property name="basePackage" value="com.bjpowernode.mapper" /><!--注入SqlSessionFactoryBean 用于创建SqlSession --><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!-- 配置Service 层对象 --><bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" /></beans>

5.2 Spring配置文件版

使用Spring的配置文件,取代mybatis的核心配置文件。

导入的jar包和相关类完全一致,jdbc配置文件和日志配置文件也相同。只是将mybatis的核心配置文件中的配置,移入到spring的核心配置文件中。

5.2.1 Spring核心配置文件

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--终极目标 为 每个service 注入一个Mapper 对象1. Mapper 对象2. SqlSession 获取3. SqlSession 要根据 SqlSessionFactory 获取4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器6. 配置数据源--><!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性--><context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" /><!--2. 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!--3. 配置SqlSessionFactoryBean 对象--><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><!--  配置数据源 --><property name="dataSource" ref="dataSource" /><!-- 配置包下类别名 多个包之间使用 逗号分隔 --><property name="typeAliasesPackage" value="com.bjpowernode.domain" /><!-- 配置插件 --><property name="plugins"><array><bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" /></array></property><!-- 配置映射文件 --><property name="mapperLocations" value="mapper/**/*Mapper.xml"></property></bean><!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 --><property name="basePackage" value="com.bjpowernode.mapper" /><!--注入SqlSessionFactoryBean 用于创建SqlSession --><!--SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean区分数据源--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!-- 配置Service 层对象 --><bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" /></beans>

5.2.2 配置日志

<?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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--终极目标 为 每个service 注入一个Mapper 对象1. Mapper 对象2. SqlSession 获取3. SqlSession 要根据 SqlSessionFactory 获取4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器6. 配置数据源--><!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性--><context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" /><!--2. 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置 Configuration--><bean  id="configuration" class="org.apache.ibatis.session.Configuration"><!-- 指定日志工具 --><property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" /><!-- 配置缓存 --><property name="cacheEnabled" value="true" /></bean><!--3. 配置SqlSessionFactoryBean 对象--><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><!--  配置数据源 --><property name="dataSource" ref="dataSource" /><!-- 配置包下类别名 多个包之间使用 逗号分隔 --><property name="typeAliasesPackage" value="com.bjpowernode.domain" /><!-- 配置插件 --><property name="plugins"><array><bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" /></array></property><!-- 注入configuration --><property name="configuration"  ref="configuration" /><!-- 配置映射文件 --><property name="mapperLocations" value="mapper/**/*Mapper.xml"></property></bean><!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 --><property name="basePackage" value="com.bjpowernode.mapper" /><!--注入SqlSessionFactoryBean 用于创建SqlSession --><!--SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean区分数据源--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!-- 配置Service 层对象 --><bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" /></beans>

6.声明式事务

在spring中,spring可以管理数据源,管理连接,spring也可以管理事务,并且spring单独对事务分了一个模块进行管理。并且,Spring简化了事务开发,只需要通过配置的方式,Spring即可对事务进行统一完善的管理,Spring的事务管理基于Spring的AOP技术。

Spring的声明式事务,有两种方式:xml配置、注解

6.1 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: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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--终极目标 为 每个service 注入一个Mapper 对象1. Mapper 对象2. SqlSession 获取3. SqlSession 要根据 SqlSessionFactory 获取4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器6. 配置数据源--><!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性--><context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" /><!--2. 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置 Configuration--><bean  id="configuration" class="org.apache.ibatis.session.Configuration"><!-- 指定日志工具 --><property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" /><!-- 配置缓存 --><property name="cacheEnabled" value="true" /></bean><!--3. 配置SqlSessionFactoryBean 对象--><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><!--  配置数据源 --><property name="dataSource" ref="dataSource" /><!-- 配置包下类别名 多个包之间使用 逗号分隔 --><property name="typeAliasesPackage" value="com.bjpowernode.domain" /><!-- 配置插件 --><property name="plugins"><array><bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" /></array></property><!-- 注入configuration --><property name="configuration"  ref="configuration" /><!-- 配置映射文件 --><property name="mapperLocations" value="mapper/**/*Mapper.xml"></property></bean><!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 --><property name="basePackage" value="com.bjpowernode.mapper" /><!--注入SqlSessionFactoryBean 用于创建SqlSession --><!--SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean区分数据源--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!-- 配置Service 层对象 --><bean id="userService" class="com.bjpowernode.service.impl.UserServiceImpl" autowire="byType" /><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 配置数据源  指定要管理那个数据源的事务 --><property name="dataSource" ref="dataSource" /></bean><!-- 配置事务增强 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><!-- 配置增强规则 --><tx:attributes><!--name : 进行数据库操作方法的名称  add* 表示 add开头的方法  * 指代任意字符propagation : 事务传播性  面试重点read-only : 只读事务  默认 falserollback-for : 指定回滚的异常  默认是 RunTimeException 下的异常会自动回滚no-rollback-for : 不回滚的异常timeout : 事务的超时时间isolation : 事务隔离级别  面试重点| 1. 读未提交| 2. 读已提交| 3. 可重复读| 4. 串行化--><tx:method name="add*" read-only=”false” rollback-for="Exception"/><tx:method name="insert*" rollback-for="Exception" /><tx:method name="update*" rollback-for="Exception" /><tx:method name="delete*" rollback-for="Exception" /><tx:method name="*" read-only="true" /></tx:attributes></tx:advice><!-- 配置切面 --><aop:config><!-- 注意一般切点在 service --><aop:pointcut id="mypoint" expression="execution(* com.bjpowernode.service.impl.*.*(..))"/><!-- 织入增强 --><aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" /></aop:config>
</beans>

6.2 注解版声明式事务

在Spring中,为简化事务开发,提供了注解:@Transactional,该注解可以指定在类上,在类上,该类中的所有方法都会使用事务,该注解也可以指定方法上,该方法会使用事务。使用非常简单,只需:

  1. 配置事务管理器

  2. 开启注解事务

  3. 在需要使用事务的地方使用@Transactional

6.2.1 配置类

<?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: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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--终极目标 为 每个service 注入一个Mapper 对象1. Mapper 对象2. SqlSession 获取3. SqlSession 要根据 SqlSessionFactory 获取4. SqlSessionFactory 要 根据 SqlSessionFactoryBuilder获取5. SqlSessionFactoryBuilder 可以直接创建 此时需要使用IOC容器6. 配置数据源--><!--1. 引入jdbc的配置文件 使用配置文件 不是使用系统属性--><context:property-placeholder location="jdbc.properties" system-properties-mode="FALLBACK" /><!--2. 配置数据源 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置 Configuration--><bean  id="configuration" class="org.apache.ibatis.session.Configuration"><!-- 指定日志工具 --><property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" /><!-- 配置缓存 --><property name="cacheEnabled" value="true" /></bean><!--3. 配置SqlSessionFactoryBean 对象--><bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"><!--  配置数据源 --><property name="dataSource" ref="dataSource" /><!-- 配置包下类别名 多个包之间使用 逗号分隔 --><property name="typeAliasesPackage" value="com.bjpowernode.domain" /><!-- 配置插件 --><property name="plugins"><array><bean id="pageInterceptor" class="com.github.pagehelper.PageInterceptor" /></array></property><!-- 注入configuration --><property name="configuration"  ref="configuration" /><!-- 配置映射文件 --><property name="mapperLocations" value="mapper/**/*Mapper.xml"></property></bean><!-- 4.扫描所有的Mapper接口 自动创建Mapper的代理对象  --><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!-- 待扫描的mapper 接口的包名 多个之间使用逗号分隔 --><property name="basePackage" value="com.bjpowernode.mapper" /><!--注入SqlSessionFactoryBean 用于创建SqlSession --><!--SqlSessionFactoryBean 是可以自动装配的 但是 如果存在多个数据源时,可以指定SqlSessionFactoryBean区分数据源--><property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" /></bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 配置数据源  指定要管理那个数据源的事务 --><property name="dataSource" ref="dataSource" /></bean><!-- 开启组件扫描 --><context:component-scan base-package="com.*" /><!-- 开启事务注解 --><tx:annotation-driven transaction-manager="transactionManager"  />
</beans>

6.2.2 service代码

package com.bjpowernode.service.impl;import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper  userMapper;@Overridepublic User queryUser(Integer id) {return userMapper.selectById(id);}@Overridepublic PageInfo<User> queryPage(Integer page,Integer limit) {Page<User> users = PageHelper.startPage(page, limit);userMapper.selectAll();return users.toPageInfo();}/***  在spring中 不要在事务相关方法中 使用catch 处理*  如果处理了  异常不会被spring aop 增强的方法 捕获到  不会回滚*  事务配置就失效了  所以如果有异常 :*  1. 直接抛*  2. 在catch继续抛出异常* @param user* @return*/@Override//@Transactional(rollbackFor = Exception.class)public Integer addUser(User user) {int m = userMapper.insert(user);int n = 0;try {m = m/n;//出现异常} catch (Exception exception) {exception.printStackTrace();throw new RuntimeException("发生 请求回滚!!!");}return m;}
}

7
在这里插入图片描述

注意:

事务的传播行为,是指事务会发生传递。例如:A方法存在事务,A调用B方法,那么B方法也会在事务中执行,这种就是事务的传播行为。

package com.bjpowernode.controller;import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;@Controller
public class UserController {@Autowiredprivate IUserService  userService;@Autowiredprivate UserMapper userMapper;@Transactionalpublic void add(User user){User user1 = new User();user1.setUsername("韩梅梅");user1.setPassword("123");user1.setRealname("韩梅梅");userMapper.insert(user1);//在父事务中添加数据  自己的程序 更新数据状态try {//其他的业务操作userService.addUser(user);//子事务  子事务发生异常}catch (Exception e){e.printStackTrace();}int n = 0;//n = 100/n;//出现异常}
}package com.bjpowernode.service.impl;import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper  userMapper;@Overridepublic User queryUser(Integer id) {return userMapper.selectById(id);}@Overridepublic PageInfo<User> queryPage(Integer page,Integer limit) {Page<User> users = PageHelper.startPage(page, limit);userMapper.selectAll();return users.toPageInfo();}/***  在spring中 不要在事务相关方法中 使用catch 处理*  如果处理了  异常不会被spring aop 增强的方法 捕获到  不会回滚*  事务配置就失效了  所以如果有异常 :*  1. 直接抛*  2. 在catch继续抛出异常* @param user* @return*/@Override//@Transactional(propagation = Propagation.SUPPORTS) //有就在事务中执行  没有就不在事务中执行//@Transactional(propagation = Propagation.MANDATORY) //必须要有事务//@Transactional(propagation = Propagation.NEVER) // 不在事务中执行  当前存在事务就报错@Transactional(propagation = Propagation.NESTED) // 当前存在一个事务 就 创建一个子事务 嵌套在当前事务中//外层事务出现异常会回滚子事务   子事务出现异常 不会回滚外层事务public Integer addUser(User user) {int m = userMapper.insert(user);int n = 0;m = m/n;//出现异常return m;}
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/158106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux docker安装RStudio Server结合内网穿透实现公网访问内网服务

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅cpolar &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言1. 安装RStudio Server2. 本地访问3. Linux 安装cpolar4. 配置RStudio server公网访问地址5…

kibana 7安装

手动安装 下载 wget https://artifacts.elastic.co/downloads/kibana/kibana-7.17.15-linux-x86_64.tar.gz 解压 mv kibana-7.17.15-linux-x86_64.tar.gz /usr/local tar -zxvf kibana-7.17.15-linux-x86_64.tar.gz chown -R es:es kibana-7.17.15-linux-x86_64修改配置 s…

解决VSCode运行时自动保存问题【图文解析】

用VSCode写前端时老是自动保存&#xff0c;代码还没写完就开始 刷新页面 调用接口 出现报错之类的&#xff0c;很烦人&#xff0c;所以就写一篇修改VSCode自动保存文件的文章&#xff0c;以免自己忘记在哪设置。 同事总是用不自动保存&#xff0c;每次写完都要ctrls一下&#x…

电脑文件夹加密怎么操作?保护数据4个方法分享!

“大家平常是怎么给电脑文件夹加密的呀&#xff1f;我有一些比较重要的数据&#xff0c;为了不让别人看到&#xff0c;我想把它们加密&#xff0c;应该怎么操作呢&#xff1f;” 平常使用电脑时&#xff0c;可能很多朋友会将很多重要的数据保存在电脑上。但是有些文件对用户来说…

私有化敏感词检测API服务wordscheck

之前有网友在找敏感词检测的应用&#xff0c;这个应该能满足他的需求&#xff1b; 什么是 wordscheck &#xff1f; wordscheck 是敏感词检测 API&#xff0c;提供文本识别、智能鉴黄、涉政检测、谩骂等等敏感词检测过滤服务。 简介 敏感词库从大量样本库整理出来&#xff0c;…

bootstarp+springboot基于Java的教学仪器设备商城销售网站_o9b00

1、商品分类功能 商品分类是教学仪器设备销售网站中十分重要的一部分&#xff0c;它能够提高用户在网站上的浏览速度&#xff0c;并方便用户快速找到自己需要的商品。因此&#xff0c;需要对该功能进行分析和设计&#xff0c;确保其体验性、可用性和易用性。可以将商品分为多个…

Apache服务Rwrite功能使用

Rewrite也称为规则重写&#xff0c;主要功能是实现浏览器访问时&#xff0c;URL的跳转。其正则表达式是基于Perl语言。要使用rewrite功能&#xff0c;Apache服务器需要添加rewrite模块。如果使用源码编译安装&#xff0c;–enable-rewrite。有了rewrite模块后&#xff0c;需要在…

驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接

参考&#xff1a;https://www.cnblogs.com/sam-snow-v/p/15917898.html eclipse链接SQL Server出现问题 笔者使用Open JDK 17&#xff0c;SQL Server 2016&#xff0c;项目中使用JPA操作数据库。测试环境没问题&#xff0c;生产环境出现如题所示“驱动程序无法通过使用安全套接…

无痛迁移:图解 Kubernetes 集群升级步骤

本文探究了 Kubeadm 集群升级工作流程&#xff0c;并以可视化方式展现。着重介绍了控制平面节点和工作节点的升级步骤&#xff0c;涵盖了 kubeadm 升级、节点清空、kubelet 和 kubectl 升级&#xff0c;以及解除节点封锁的关键步骤。 这个简明扼要的指南可帮助用户理解和执行 K…

苹果Siri怎么打开?教你两招轻松唤醒!

苹果Siri助手是苹果公司开发的智能语音助手。作为智能语音助手&#xff0c;Siri可以理解用户的指令&#xff0c;并给出相应的回答或执行相应的操作&#xff0c;帮助大家完成各种任务&#xff0c;比如发送短信、查询天气、播放音乐、设置提醒等等。 然而&#xff0c;还有一些小…

几个西门子PLC常见通讯问题的解决方法

1台200SMART 如何控制2台步进电机&#xff1f; S7-200SMART CPU最多可输出3路高速脉冲&#xff08;除ST20外&#xff09;&#xff0c;这意味着可同时控制最多3个步进电机&#xff0c;通过运动向导可配置相应的运动控制子程序&#xff0c;然后通过调用子程序编程可实现对步进电…

数据分析思维与模型:相关分析法

相关分析法是一种用于研究两个或多个变量之间关系强度和方向的统计方法。这种方法在多个领域&#xff0c;如经济学、心理学、社会科学和自然科学中都有广泛应用。其核心是通过计算相关系数来量化变量之间的相关性。以下是相关分析法的一些基本概念和步骤&#xff1a; 选择变量…

【Mysql系列】LAG与LEAD开窗函数

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

用合成数据训练语义分割模型【裂缝检测】

最近&#xff0c;我们推出了合成裂缝分割数据集&#xff0c;在本文中&#xff0c;我们将深入探讨应用于合成数据生成过程的改进和启发式方法。 阅读完这篇文章后&#xff0c;你将了解我们如何设法创建一个数据集&#xff0c;该数据集可以像使用真实数据一样高效地训练模型。 在…

【Python】【Torch】神经网络中各层输出的特征图可视化详解和示例

本文对神经网络各层特征图可视化的过程进行运行示例&#xff0c;方便大家使用&#xff0c;有助于更好的理解深度学习的过程&#xff0c;尤其是每层的结果。 神经网络各层特征图可视化的好处和特点如下&#xff1a; 可视化过程可以了解网络对图像像素的权重分布&#xff0c;可…

PyCharm玩转ESP32

想必玩ESP32的童鞋都知道Thonny&#xff0c;当然学Python的童鞋用的更多的可能是PyCharm和VsCode Thonny和PyCharm的对比 对于PyCharm和VsCode今天不做比较&#xff0c;今天重点说一下用PyCharm玩转ESP32&#xff0c;在这之前我们先对比下Thonny和PyCharm的优缺点 1、使用Tho…

【HarmonyOS】低代码平台组件拖拽使用技巧之常用基础组件(下)

【关键字】 HarmonyOS、低代码平台、组件拖拽、代码编辑器 1、写在前面 本篇接着上一篇的内容来介绍&#xff0c;继续来看我们的登录页面的下半部分的使用&#xff0c;本篇会介绍按钮组件、单选框组件的拖拽使用&#xff0c;还会介绍代码编辑器的使用&#xff0c;最后会完成登…

【云栖 2023】姜伟华:Hologres Serverless 之路——揭秘弹性计算组

云布道师 本文根据 2023 云栖大会演讲实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a;姜伟华 | 阿里云计算平台事业部资深技术专家、阿里云实时数仓 Hologres 研发负责人 演讲主题&#xff1a;Hologres Serverless 之路——揭秘弹性计算组 实时化成为…

PDF文件无密码,如何解密?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。想要解密&#xff0c;我们需要输入正确的密码&#xff0c;但是有时候我们可能会出现忘记密码的情况&#xff0c;或者网上下载P…

怎么做好品牌营销,小红书爆款笔记怎么做?

只要在小红书平台进行传播&#xff0c;能够尽可能多的创造爆款笔记&#xff0c;就是所有品牌方和达人的目标。今天来马文化传媒为大家分享下怎么做好品牌营销&#xff0c;小红书爆款笔记怎么做&#xff1f; 一、判断爆款笔记的三大指标 判断一篇笔记是否是爆款笔记&#xff0c;…