狂神Spring学习笔记

一:Spring
- Spring: 春天 -> 给软件行业带来了春天
- 2002,首次推出了Spring框架的雏形: interface21
- 2004年3月24,发布了1.0正式版
- Rod Johnson -> Spring framework创始人
- 理念:使现有的技术更加容易使用, 本身是一个大杂烩,整合了现有的技术框架
- Spring是一个开源的免费的框架(容器),是一个轻量级的、非入侵式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
Spring就是一个轻量级的控制反转(IOC)和面向切面免除(AOP)的框架
SSH: Struct2 + Spring + Hibernate
SSM: SpringMvc + Spring + MyBatis
pom.xml 依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
二:IOC
(一)理论推导
1.UserDao 接口
2.UserDaoImpl 实现类
3.UserService 业务接口
4.UserServiceImpl 业务实现类
在我们之前的业务中,用户的需求可能会影响原来的代码,我们需要根据用户的需求去修改源代码。如果程序代码量十分大,修改一次的成本代价十分昂贵。
使用一个set接口实现,已经发生了革命性的变化。
private UserDao userDao;
// 利用set实现动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象,控制权在程序员手上
- 使用set注入后,程序不在具有主动性,而是变成了被动的接受对象
思想的差距不是在短期内能够弥补的
这种思想,从本质上解决了问题,程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上,这是IOC的原型
程序完全不用动,修改配置xml文件中进行修改,对象由Spring来创建、管理、装配
beans.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="mysqlImpl" class="com.kuang.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="com.kuang.dao.UserDaoOracleImpl"/>
<bean id="UserServiceImpl" class="com.kuang.service.UserServiceImpl">
<!-- ref: 是引用spring容器中创建好的对象
value: 具体的值
-->
<property name="userDao" ref="oracleImpl"/>
</bean>
</beans>
测试
public class MyTest {
public static void main(String[] args) {
// 用户实际调用的是业务层, dao层不需要接触
// UserServiceImpl userService = new UserServiceImpl();
// userService.setUserDao(new UserDaoMysqlImpl());
// userService.getUser();
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("UserServiceImpl");
userServiceImpl.getUser();
}
}
(二)IOC创建对象的方式
1.使用无参构造创建对象,默认
2.假设要使用有参构造创建对象
- 下标赋值
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg index="0" value="夜斗学java"/>
</bean>
- 通过类型创建
<!-- 通过类型创建-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg type="java.lang.String" value="夜斗学java"/>
</bean>
- 通过参数名
<!-- 直接通过参数名来设置-->
<bean id="user" class="com.kuang.pojo.User">
<constructor-arg name="name" value="币圈好难受"/>
</bean>
(三)Bean的配置
<!-- id: bean的唯一标识符
class: bean对象所对应的全限定符
name: 别名-->
<bean id="userT" class="com.kuang.pojo.UserT" name="yedou1">
<constructor-arg name="name" value="币圈好难受" />
</bean>
<!-- 取别名-->
<alias name="user" alias="yedou"/>
(四)import
一般用于团队开发,将多个配置文件,导入合并为一个总的配置
<?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="beans.xml"/>
<import resource="beans1.xml"/>
</beans>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User)context.getBean("user");
user.show();
}
}
三:依赖注入
- 构造器注入
- Set方式注入
- 拓展方式注入
(一)set方式注入
- 依赖: bean对象的创建依赖于容器
- 注入: bean对象中的所有属性,由容器来注入
【环境搭建】
1.复杂类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.真实测试对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
}
3.beans.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="student" class="com.kuang.pojo.Student">
<property name="name" value="夜斗"/>
</bean>
</beans>
4.测试类
public class YeTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
完善注入信息
<bean id="address" class="com.kuang.pojo.Address">
<property name="address" value="夜斗小神社"/>
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<property name="name" value="夜斗"/>
<property name="address" ref="address"/>
<property name="books">
<array>
<value>吕氏春秋</value>
<value>我的春秋</value>
<value>我做主</value>
<value>!</value>
</array>
</property>
<property name="hobbys">
<list>
<value>写代码</value>
<value>看电影</value>
<value>听歌</value>
</list>
</property>
<property name="card">
<map>
<entry key="身份证" value="12345"/>
<entry key="银行卡" value="45678"/>
</map>
</property>
<property name="games">
<set>
<value>荒野大表哥</value>
<value>英雄联盟</value>
<value>BOB</value>
</set>
</property>
<property name="wife">
<null/>
</property>
<property name="info">
<props>
<prop key="学号">190370063</prop>
<prop key="url">baidu</prop>
<prop key="username">夜斗</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
(二)p命名和c命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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">
<!-- p命名空间注入:可以直接注入属性的值-->
<bean id="user" class="com.kuang.pojo.User" p:name="夜斗" p:age="21" />
<!-- c命名空间注入,通过构造器注入-->
<bean id="user2" class="com.kuang.pojo.User" c:age="18" c:name="狂神"/>
</beans>
四:Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式
- Spring会在上下文中自动寻找,并给bean装配属性
在Spring中有三种自动装配的方式
- 在xml中显示的配置
- 在java中显示配置
- 隐式的自动装配bean
(一):byname与bytype自动装配
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<!-- byName: 会自动在容器上下文中查找,和自己对象set方法后面的值对应的 beanid
byType: 会自动在容器上下文中查找, 和自己对象属性类型相同的bean
-->
<bean id="people" class="com.kuang.pojo.People" autowire="byType">
<property name="name" value="夜斗"/>
<!-- <property name="dog" ref="dog"/>-->
<!-- <property name="cat" ref="cat"/>-->
</bean>
(二):注解实现自动装配
jdk1.5支持的注解,Spring2.5就支持注解了
使用注解:
1.导入约束:context约束
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
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解的支持-->
<context:annotation-config/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="people" class="com.kuang.pojo.People">
</bean>
</beans>
@Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法,前提是你这个自动装配在IOC容器中存在
@Nullable 字段标记了这个注解,说明这个字段可以为null
public class People {
// 这个对象可以为空值
@Autowired(required = false)
private Cat cat;
@Autowired
@Qualifier(value="dog222")
private Dog dog;
private String name;
}
五:使用注解开发
在Spring4之后,要使用注解开发,必须要保证aop的包导入了
使用注解要增加context约束,增加注解的支持
1.bean
<!-- 指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
<!-- 开启注解的支持-->
<context:annotation-config/>
@Component
public class User {
@Value("yedou")
public String name;
}
2.属性如何注入
public class User {
@Value("yedou")
public String name;
}
3.衍生注解
@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层
- dao(@Repository)
- service(@Service)
- controller(@Controller)
这四个注解的功能都是一样的,都是代表将某个类注册到Spring中,装备到Bean
xml与注解:
- xml更加万能,适用于任何场合,维护简单方便
- 注解不是类使用不了,维护相对复杂
Xml与注解最佳实践
- xml用于管理bean
- 注解只负责完成属性的注入
- 必须让注解生效,就需要开启注解的支持
六:使用Java的方式配置Spring
我们现在完全不使用Spring的Xml的配置了,全程交给java来做
JavaConfig是Spring的一个子项目,在Spring4之后,他成为了一个核心功能
实体类
package com.kuang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
// 这个类被Spring接管了,注册到了容器中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("yedou")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
package com.kuang.config;
import com.kuang.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
// 代表这是一个配置类,就和之前beans.xml一样
@Configuration
@ComponentScan("com.kuang.pojo")
@Import(YeConfig2.class)
public class YeConfig {
// 注册一个Bean,就相当于我们之前写的一个bean标签
// 这个方法的名字就相当于bean标签中的id属性
// 这个方法的返回值就相当于bean标签中的class属性
@Bean
public User getuser(){
// 要注入到bean的对象
return new User();
}
}
测试类
import com.kuang.config.YeConfig;
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
// 如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(YeConfig.class);
User getUser = (User) context.getBean("getuser");
System.out.println(getUser.getName());
}
}
这种纯java的配置方式,在SpringBoot中随处可见!
六:代理模式
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP和SpringMVC】
代理模式的分类:
- 静态代理
- 动态代理
(一)静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理角色:代理真实的角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
1.接口
public interface Rent {
public void rent();
}
2.真实角色
// 房东
public class Host implements Rent{
public void rent() {
System.out.println("房东要出租房子");
}
}
3.代理角色
public class Proxy implements Rent{
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent() {
seeHouse();
host.rent();
hetong();
fare();
}
// 看房
public void seeHouse(){
System.out.println("中介带你看房");
}
// 收中介费
public void fare(){
System.out.println("收中介费");
}
// 签合同
public void hetong(){
System.out.println("收中介费");
}
}
4.客户端访问代理角色
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
代理模式的好处:
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
- 公共也就交给代理角色,实现了业务的分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率会变低
(二)动态代理
- 动态代理和静态代理角色一样
- 动态代理的代理是动态生成的,不是我们直接写好的
- 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
基于接口: JDK动态代理
基于类:cglib
java字节码实现:javasist
需要了解两个类:Proxy — 代理 InvocationHandler:调用程序
动态代理的好处:
- 一个动态代理类代理的是一个接口,一般就是一类业务
- 一个动态代理类可以代理多个类,只要实现了同一个接口即可
七: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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--<!– 方式一:使用原生Spring API接口–>-->
<!-- <aop:config>-->
<!--<!– 切入点–>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>-->
<!--<!– –>-->
<!--<!– 执行环绕增强–>-->
<!-- <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>-->
<!-- <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>-->
<!-- </aop:config>-->
<!-- 方式二:自定义类-->
<bean id="diy" class="com.kuang.diy.DiyPointCut"/>
<aop:config>
<!-- 自定义切面,ref 要引用的类-->
<aop:aspect ref="diy">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
八:整合Mybatis
步骤:
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>com.kuang</groupId>
<artifactId>spring-study</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>spring-01-ioc1</module>
<module>spring-02-hellospring</module>
<module>spring-03-ioc2</module>
<module>spring-04-di</module>
<module>spring-05-Autowired</module>
<module>spring-06-anno</module>
<module>spring-07-appconfig</module>
<module>spring-08-proxy</module>
<module>spring-09-aop</module>
<module>spring-10-mybatis</module>
</modules>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.23</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
</project>
2.编写配置文件
1.编写数据源配置
2.sqlSessionFactory
3.sqlSessionTemplate
4.给接口增加实现类
5.将自己写的实现类,注入到Spring中
6.测试
九:声明式事务
- 把一组业务当成一个业务来做;要么都成功,要么都失败!
- 事务在项目开发中,十分的重要,涉及到数据一致性问题,不能马虎!
- 确保完整性和一致性;
事务ACID原则:
- 原子性
- 一致性
- 隔离性:多个业务可能操作同一个资源,防止数据损坏
- 持久性:事务一旦提交,无论系统发生什么问题,结果都不会被影响,被持久化的写到存储器中
(一):spring中的事务管理
声明式事务;AOP
编程式事务:
<!-- 配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>
<!-- 结合AOP实现事物的织入-->
<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 给哪些方法配置事务-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
<!-- <tx:method name="delete"/>-->
<!-- <tx:method name="update"/>-->
<!-- <tx:method name="query"/>-->
<!-- <tx:method name="*"/>-->
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPoint" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
</beans>