spring


spring

狂神说spring笔记

优点

  • ==控制反转(IOC),面向切面编程(AOP)==

  • 支持事物的处理,对框架整合的支持

spring boot

  • 快速开发脚手架
  • 快速开发单个微服务
  • 约定大于配置

学习springboot的前提是spring和springMVC

一、IOC

set接口实现

1
2
3
4
5
private UserDao userDao;
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}

主动权(控制权)由程序员变为了用户,实现了==控制反转==

程序不再具有主动性,变为了被动的接收对象

本质

是spring的核心内容,是一种设计思想,其实现方法是依赖注入(DI)

控制反转就是获得对象的方式反转了

HelloSpring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--使用spring来创建对象,在spring中这些都称为Bean

类型 变量名 = new 类型();
Hello hello = new Hello();
bean = 对象 new Hello();

id = 变量名
class = new的对象
property 相当于给对象中的属性设置的一个值

-->
<bean id="hello" class="com.nuc.Hello">
<property name="str" value="Spring"/>
</bean>

hello的对象是由spring创建的

hello的属性是由spring容器设置的

这个过程就是控制反转

  • 控制:谁来控制对象的创建,传统中是由程序本身控制创建的,使用spring之后,对象是由spring创建的

  • 反转:就是程序本身不创建对象,而变为被动的接收对象

  • 依赖注入:本质就是利用set方式注入

IOC是一种编程思想,由主动的编程变为被动的接收

要实现不同的操作只需要在xml配置文件中进行修改,所谓的IOC就是:==对象由spring来创建,管理,装配==

src/main/resources bean.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--使用spring来创建对象,在spring中这些都称为Bean-->

<bean id="mysqlImpl" class="com.nuc.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="com.nuc.dao.UserDaoOracleImpl"/>

<!--
ref:引用spring容器中创建好的对象
value:是具体的值,基本数据类型
-->

<bean id="UserServiceImpl" class="com.nuc.service.UserServiceImpl">
<property name="userDao" value="mysqlImpl"/>
</bean>

src/test/java MyTest.java

1
2
3
4
5
6
7
8
9
10
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象(获取ApplicationContext:拿到spring的容器)
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

//对象在spring中管理,要使用直接get取出来就可以
Hello hello = (Hello)context.getBean("hello");
System.out.println(hello.toString());
}
}

IOC创建对象方式

  1. 默认采用无参构造创建对象

  2. 使用有参构造创建对象

    1. 下标赋值
    1
    2
    3
    <bean id="user" class="com.nuc.User">
    <constructor-arg index="0" value="姓名"/>
    </bean>
    1. 类型
    1
    2
    3
    4
    <!--    第二种:通过类型创建,不推荐使用-->
    <bean id="user" class="com.nuc.User">
    <constructor-arg type="java.lang.String" value="姓名2"/>
    </bean>
    1. 直接通过参数名来创建(重点掌握)
    1
    2
    3
    4
    <!--    第三种:直接通过参数名来创建-->
    <bean id="user" class="com.nuc.User">
    <constructor-arg name="name" value="姓名3"/>
    </bean>

    在配置文件加载的时候,spring容器中的管理的对象就已经初始化了

二、spring配置

别名

1
2
3
通过别名可以获取到这个对象
<alias name="user" alias="userNew">
name

bean的配置

1
2
3
4
5
6
7
8
9
<!--
id :bean的唯一标识,相当于对象名
class: bean对象所对应的全限定名:包名+类型
name: 别名,name可以取多个别名
-->

<bean id="userT" class="com.nuc.UserT" name="user2,u2,u3" >
<property name="name" value="别名"/>
</bean>

import

一般用于团队开发;项目中多个配置文件bean.xml时,使用import将所有的导入到总的applicationContext.xml

1
2
3
<import resource=bean1.xml>
<import resource=bean2.xml>
<import resource=bean3.xml>

三、依赖注入DI(DI)

image-20211121184028889

1.构造器注入

2.set注入(重点)

本质:set注入

  • 依赖:bean对象的==创建==依赖于容器
  • 注入:bean对象中的所有属性,由==容器==来注入

环境搭建

image-20211115183858382

(1)复杂类型
1
2
3
4
5
6
7
8
9
10
11
12
public class Address {

private String address;

public String getAddress(){
return address;
}

public void setAddress(String address) {
this.address = address;
}
}
(2)真实测试对象
1
2
3
4
5
6
7
8
9
10
11
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;
//get、set方法
}
(3)beans.xml
1
2
3
4
5
6
7
8
9
10
<?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.nuc.Student">
<!-- 第一种:普通值注入,value-->
<property name="name" value="姓名"/>
</bean>
</beans>
(4)测试类
1
2
3
4
5
6
7
8
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

Student student = (Student) context.getBean("student");
System.out.println(student.getName());
}
}
(5)完善注入信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<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="address" class="com.nuc.Address">
<property name="address" value="长春"/>
</bean>

<bean id="student" class="com.nuc.Student">
<!-- 第一种:普通值注入,value-->
<property name="name" value="姓名"/>

<!-- 第二种:bean注入,ref-->
<property name="address" ref="address"/>

<!-- 第三种:数组注入-->
<property name="books">
<array>
<value>java疯狂讲义</value>
<value>python从零到一</value>
<value>C++从入门到精通</value>
</array>
</property>

<!-- list注入-->
<property name="hobbys">
<list>
<value>学习</value>
<value>游戏</value>
<value>娱乐</value>
</list>
</property>

<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="123123123"/>
<entry key="银行卡" value="111111111"/>
</map>
</property>

<!-- Set-->
<property name="games">
<set>
<value>lol</value>
<value>gtf5</value>
<value>csgo</value>
</set>
</property>

<!-- null-->
<property name="wife" >
<null></null>
</property>

<!-- Properties-->
<property name="info">
<props>
<prop key="学号">20200101</prop>
<prop key="性别"></prop>
<prop key="姓名">张三</prop>
</props>
</property>
</bean>

</beans>

3.扩展方式注入

使用p命名空间和c命名空间进行注入

1
2
3
4
5
6
7
8
9
10
11
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" xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- p命名空间注入,可以直接注入属性的值-->
<bean id="user" class="com.nuc.User" p:name="姓名1" p:age="23"/>
<!-- c命名空间注入,通过构造器注入:construct-arg-->
<bean id="user2" class="com.nuc.User" c:age="26" c:name="姓名2"/>

</beans>

测试:

1
2
3
4
5
6
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2",User.class);
System.out.println(user);
}

注:p命名和c命名不能直接使用,需要导入xml约束

4. bean的作用域

(1)单例模式(spring默认机制)
1
<bean id="user2" class="com.nuc.User" c:age="26" c:name="姓名2" scope="singleton"/>
(2)原型模式(每次从容器中get时都会产生一个新对象)
1
<bean id="user2" class="com.nuc.User" c:age="26" c:name="姓名2" scope="prototype"/>

(3)其余的request、session、application(只在web开发中使用)

四、bean的自动装配(autowired)重点

image-20211121184123368

  • 自动装配是spring满足bean依赖的一种方式
  • spring会在上下文中自动寻找,并给bean装配属性

在spring中的三种装配方式:

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean(重要)

1.测试

环境搭建:一个人有两个宠物

2.ByName自动装配

1
2
3
4
5
6
<!--    byName:会自动在容器上下文中寻找,和自己对象set方法后面的值对应的bean id-->
<bean id="people" class="com.nuc.People" autowire="byName">
<property name="name" value="狂神Nb"/>
<!-- <property name="dog" ref="dog"/>-->
<!-- <property name="cat" ref="cat"/>-->
</bean>

3.ByType自动装配

1
2
3
4
5
6
<!--    byName:会自动在容器上下文中寻找,和自己对象属性类型相同的bean-->
<bean id="people" class="com.nuc.People" autowire="byType">
<property name="name" value="狂神Nb"/>
<!-- <property name="dog" ref="dog"/>-->
<!-- <property name="cat" ref="cat"/>-->
</bean>
  • byname时,要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致
  • bytype时,要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

4.使用注解实现自动注入

jdk1.5 spring2.5

使用注解需要:

  1. 导入约束(context约束)
  2. 配置注释的支持==<context:annotation-config/>==

@Autowired

直接在属性或在set方式上使用

使用@Autowired可以不用编写set方法,前提是这个自动装配的属性在IOC(spring)容器中存在,且符合名字byname

如果@Autowired自动装配的环境比较复杂,无法通过一个注释@Autowired完成时,可以使用**@Qualifier(value=”xxx”)**去配置@Autowired的使用,指定唯一的bean对象注入

@Resource 和 @Autowired的区别:

image-20211119195809980

注解说明

image-20211119195617984

五、使用注解开发(anno)

spring4之后,要使用注解开发,要导入aop的包

使用注释需要导入context约束,增加注解的支持

1
2
3
4
5
6
7
8
9
10
11
<?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:annotation-config/>


</beans>

@Component:组件,放在类上,说明这个类被spring管理了即bean

1.bean

2.属性如何注入

1
2
3
4
5
6
7
8
9
10
11
12
//等价于<bean id = "user" class = "com.nuc.pojo.User"/>
@Component //组件
public class User {

public String name;

//相当于<property name = "name" value = "姓名1">
@Value("姓名1")
public void setName(String name) {
this.name = name;
}
}

3.衍生的注解

@Compomemt有衍生注解,在web开发中会按照MVC三层架构分层

  • dao –@Repository
  • service –@Service
  • controller –@Controller

image-20211121171959614

四个注解功能一样,都是代表将摸个类注册到spring中,装配bean

4.自动装配置

image-20211119195617984

5.作用域

1
2
3
4
5
6
7
8
9
10
11
12
@Component //组件
@Scope("prototype")
public class User {

public String name;

//相当于<property name = "name" value = "姓名1">
@Value("姓名1")
public void setName(String name) {
this.name = name;
}
}

6.小结

xml与注解:

  • xml万能,适合任何场景,维护简单
  • 注解:不是自己类使用不了,维护相对复杂

最佳实践:

xml用来管理bean

注解只负责完成属性的注入

要想要注解生效,必须开启注解的支持

1
2
3
<!--    指定要扫描的包,该包下的注解就会生效-->
<context:component-scan base-package="com.nuc"/>
<context:annotation-config/>

六、使用java的方式配置spring(appconfig)

不使用spring的xml配置,全交给java来做

JavaConfig是spring的一个子项目,在spring4之后称为了一个核心功能

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//这个注解的意思就是这个类被spring接管了,注册到了容器中
@Component
public class User {
private String name;

public String getName() {
return name;
}

@Value("姓名1") //属性注入值
public void setName(String name) {
this.name = name;
}

@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//配置类,等价于beans.xml
@Configuration //也会被spring容器托管,他本来就是一个@Component
@ComponentScan("com.nuc.pojo")
@Import(NewConfig2.class)
public class NewConfig {

//注册一个bean,相当于之前写的一个bean标签
//方法中的名字==bean id
//方法中的返回值== class属性
@Bean
public User getUser(){
return new User();//就是返回要注入带bean的对象
}

}

测试类

1
2
3
4
5
6
7
8
9
10
public class MyTest {
public static void main(String[] args) {

//通过AnnotationConfigApplicationContext上下文来获取容器,通过配置类的class对象加载
ApplicationContext context = new AnnotationConfigApplicationContext(NewConfig.class);

User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}

纯java的配置方式,在spring boot中随处可见

七、代理模式

中介,这是spring aop的底层

分类:

  • 静态代理
  • 动态代理

1.静态代理

角色分析:

  • 抽象角色:一般使用接口或抽象类来解决
  • 真实角色:被代理的对象
  • 代理角色:代理真实角色,一般会做一些附属操作
  • 客户:访问代理对象的人

代码步骤

  1. 接口
1
2
3
4
//租房
public interface Rent {
public void rent();
}
  1. 真实角色
1
2
3
4
5
6
//房东
public class Host implements Rent {
public void rent() {
System.out.println("房东出租房子");
}
}
  1. 代理角色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//中介
public class Proxy implements Rent{

private Host host;

public Proxy(){
}

public Proxy(Host host) {
this.host = host;
}

public void rent() {
host.rent();
seeHouse();
contract();
fare();
}

//看房
public void seeHouse(){
System.out.println("中介带客户看房");
}

//看房
public void fare(){
System.out.println("中介收中介费");
}

//看房
public void contract(){
System.out.println("签租赁合同");
}
}
  1. 客户端访问代理角色
1
2
3
4
5
6
7
8
9
10
11
12
public class Client {
public static void main(String[] args) {
//房东出租房子
Host host = new Host();
// host.rent();
//代理,中介会有一些附属操作
Proxy proxy = new Proxy(host);

//直接找中介即可
proxy.rent();
}
}

代理模式的优点:

  • 可以使真实角色操作更加纯粹,不用关注一些公共的业务
  • 公共的交给代理角色,实现了业务分工
  • 公共业务发生拓展的时候,方便集中管理

缺点:

  • 一个真实角色产生一个代理角色,代码量翻倍,开发效率降低

2.加深理解

image-20211122170329773

代码

image-20211122170435039

UserService

1
2
3
4
5
6
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}

UserServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}

public void delete() {
System.out.println("删除了一个用户");
}

public void update() {
System.out.println("修改了一个用户");
}

public void query() {
System.out.println("查询了一个用户");
}
}

UserServiceProxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class UserServiceProxy implements UserService{

private UserServiceImpl userService;

public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}

public void add() {
log("add");
userService.add();
}

public void delete() {
log("delete");
userService.add();
}

public void update() {
log("update");
userService.add();
}

public void query() {
log("query");
userService.add();
}

//日志方法
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}

Client

1
2
3
4
5
6
7
8
9
10
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
// userService.add();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);

proxy.query();
}
}

八、AOP

核心思想:

在不改变原来的代码的情况下,实现了对原有功能的增强

九、整合Mybatis

步骤

1.导入相关jar包

  • Junit
  • mybatis
  • mysql数据库
  • spring相关的
  • aop
  • mybatis-spring(new)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<dependencies>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.10</version>
</dependency>
<!-- spring操作数据库的话,需要一个spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.18.RELEASE</version>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>

</dependencies>

2.编写配置文件

3.测试

回忆mybatis

报错记录

idea连接的时候会报错

Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.

需要在mysql中配置一下时区

image-20211123111411666

连接成功

image-20211123111308331

  1. 编写实体类
1
2
3
4
5
6
@Data
public class User {
private int uid;
private String uname;
private String upassword;
}
  1. 编写核心配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--configuration核心配置文件-->
<configuration>
<!-- 别名-->
<typeAliases>
<package name="com.nuc.pojo"/>
</typeAliases>
<!--连接数据库-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
  1. 编写接口
1
2
3
4
public interface UserMapper {
public List<User> selectUser();

}
  1. 编写Mapper.xml
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace==绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.nuc.mapper.UserMapper">

<select id="selectUser" resultType="com.nuc.pojo.User">
select * from mybatis.user
</select>
</mapper>
  1. 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyTest {

@Test
public void test() throws IOException {
String resources = "mybatis-config.xml";
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sessionFactory.openSession(true);

UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUser();

for (User user : userList) {
System.out.println(user);
}


}
}

文章作者: l0odrd
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 l0odrd !
  目录