怀旧网,博客详情:Spring 详细介绍

1、Mybatis 详细介绍

2、Spring 详细介绍

3、SpringMVC 详细介绍

4、Vue 使用详细介绍

5、Spring Boot 介绍

6、Spring Boot 配置文件讲解

7、Spring Security 介绍

8、Shiro 介绍

9、Spring Boot 整合 Swagger

10、Spring Boot 任务

11、Redis 详解介绍

12、Docker 使用详细介绍

13、JVM 介绍

14、JUC并发编程

原创

Spring 详细介绍

简介

1、基础信息介绍

  • Spring : 春天--->给软件行业带来了春天!

  • 2002年,首次推出了Spring框架的雏形;interface21框架!

  • spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,与2004年3月24日发布了1.0正式版。

  • spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

  • SSH:Struct2 + Spring + Hibernate!

  • SSM:PsringMVC + Spring + Mybatis!

使用下载:

pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>6.1.4</version>
</dependency>

2、优点

image-20240406141051720

3、组成

image-20240406141144165

4、拓展

image-20240406141608692

image-20240406141649860

image-20240406141732398

image-20240406141844500

IOC(控制反转) 讲解

1、传统开发弊端

首先创建一个Maven项目

image-20240406142239564

导入spring依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.10</version> <!-- 选择与Java 8兼容的Spring版本 -->
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
    </dependencies>

image-20240406142338315

模拟一个业务场景;

代码结构:

image-20240406143343123

User类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String dataSources;
}

UserDAO

public interface UserDAO {
    // 获取一个用户
    User getUser();
}

UserDAOImpl

public class UserADOImpl implements UserDAO{
    @Override
    public User getUser() {
        return new User("mysql查询用户!");
    }
}

UserService

public interface UserService {
    // 获取用户数据并输出
    void outUserData();
}

UserServiceImpl

public class UserServiceImpl implements UserService{
    // 构建ADO对象
    private UserDAO userDAO = new UserADOImpl();

    @Override
    public void outUserData() {
        System.out.println(userDAO.getUser());
    }
}

测试:

UserService userService = new UserServiceImpl();

userService.outUserData();

image-20240406143613055

现在新增DAO的实现类了:

public class OracleUserDAOImpl implements UserDAO{
    @Override
    public User getUser() {
        return new User("oracle查询用户!");
    }
}

现在在Service想换一个实现类调用,我们就需要修改代码:

image-20240406143849977

运行测试:

image-20240406143904607

也完成了需求:

image-20240406150354859

但是这种方式,首先我们需要不断修改Service层的代码,显然不太合理,所以我们现在就可以利用IOC的思想来修改代码如下:

public class UserServiceImpl implements UserService{
    // 构建ADO对象
    private UserDAO userDAO;

    public UserServiceImpl(UserDAO userDAO){
        this.userDAO = userDAO;
    }

    @Override
    public void outUserData() {
        System.out.println(userDAO.getUser());
    }
}

需要使用哪一种,就传入对应的实例化对象就可以了,测试使用:

UserService userService = new UserServiceImpl(new UserADOImpl());
userService.outUserData();

userService = new UserServiceImpl(new OracleUserDAOImpl());
userService.outUserData();

image-20240406144246100

利用了IOC的思想就可以灵活的处理现在的这个业务场景,当我们需要那个实现的时候,就传入对应的实现即可;

image-20240406144448822

image-20240406150119908

image-20240406150407578

ioc的本质:

image-20240406150644811

2、Hello Spring

  1. 在resources目录下创建 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">

    <!-- 通过配置文件创建一个userBean的对象 id=获取时的名字 class是创建的具体类的全类名 -->
    <bean id="user" class="com.huaijiuwang.pojo.User" >
        <!-- 配置对象的属性值,注意:使用这个属性必须有对应的set方法,不然就会报错 -->
        <property name="dataSources" value="mysql驱动" />
    </bean>
</beans>
  1. 编写代码运行测试:
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");

// 输出对象数据
System.out.println(user);

image-20240406160855594

在获取一个对象:

// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
System.out.println(user);

User user1 = (User) context.getBean("user");
System.out.println(user1);

System.out.println(user == user1);

image-20240406161137437

通过测试发现:这个bean对象是一个单例的对象,始终自能返回同一个对象,要想让对象不容,就只能创建多个配置bean:

<!-- 通过配置文件创建一个userBean的对象 id=获取时的名字 class是创建的具体类的全类名 -->
<bean id="user" class="com.huaijiuwang.pojo.User" >
    <!-- 配置对象的属性值,注意:使用这个属性必须有对应的set方法,不然就会报错 -->
    <property name="dataSources" value="mysql驱动" />
</bean>

<bean id="user1" class="com.huaijiuwang.pojo.User" >
    <property name="dataSources" value="oracle驱动" />
</bean>
// 参数写当前创建的配置文件的全名
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        // 通过对象获取一个bean的实例
        User user = (User) context.getBean("user");
        System.out.println(user);

        User user1 = (User) context.getBean("user1");
        System.out.println(user1);

        System.out.println(user == user1);

image-20240406161328592

注意:对象必须有一个空参的构造方法,不然就会报错,或者创建bean的时候使用指定构造方法创建

思考问题:

image-20240406161921834

3、ICO 创建对象的方式

修改之前的实体类:

public class User {
    private String dataSources;

    public User() {
        System.out.println("执行空参构造方法!");
    }

    public User(String dataSources) {
        this.dataSources = dataSources;
        System.out.println("执行有参构造方法!");
    }

    public String getDataSources() {
        return dataSources;
    }

    public void setDataSources(String dataSources) {
        this.dataSources = dataSources;
    }

    public String toString() {
        return "User{dataSources = " + dataSources + "}";
    }
}

注册bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.huaijiuwang.pojo.User" />
</beans>
// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

image-20240406163049089

当程序一运行就执行了构造方法,说明当前的对象是在程序一启动就创建好了,现在就子需要等待用户的使用了。

// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 通过对象获取一个bean的实例
User user = (User) context.getBean("user");
System.out.println(user);

image-20240406163146637

测试,删除无参构造方法:

image-20240406163246439

程序加载的时候就直接报错了;

运行结果如下:

image-20240406163334575

bean默认是调用对象的无参构造方法,当对象没有无参构造方法时,我们就需要手动调用有参的构造方法:

调用有参构造方法有一下三种:

  1. 通过构造方法参数下标值进行调用(默认下标从0开始)
<bean id="user" class="com.huaijiuwang.pojo.User">
    <constructor-arg index="0" value="怀旧..." />
</bean>

image-20240406163814637

  1. 通过参数的类型传(不建议使用)
<bean id="user" class="com.huaijiuwang.pojo.User">
    <constructor-arg type="java.lang.String" value="怀旧666" />
</bean>

image-20240406163925065

  1. 直接通过参数名(最常用)
<bean id="user" class="com.huaijiuwang.pojo.User">
    <constructor-arg name="dataSources" value="怀旧111" />
</bean>

image-20240406164118568

4、修改之前的传统开发代码

配置文件

<!-- 创建mysql的实现 -->
<bean id="userDao" class="com.huaijiuwang.dao.UserADOImpl" />
<!-- 创建oracle的实现 -->
<bean id="oracleDao" class="com.huaijiuwang.dao.OracleUserDAOImpl" />

<!-- 创建service的bean -->
<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl">
	 <!-- 这边创建的时候就需要使用带参数的构造方法,不然就会报错
    	之前里是通过value进行复制的,这边是使用的ref给对象赋值,这边的赋值内容就是上面创建的bean的引用
    	相当于这边传入的就是上面创建的实例对象.
    -->
	<constructor-arg index="0" ref="oracleDao" />
</bean>

编写测试方法:

// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 通过对象获取一个bean的实例
UserService userService = (UserService) context.getBean("userService");
userService.outUserData();

运行输出:

image-20240406162539703

当我们想切换实现类的时候,直接修改配置文件:

<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl">
    <!-- 这边创建的时候就需要使用带参数的构造方法,不然就会报错 -->
    <constructor-arg index="0" ref="userDao" />
</bean>

image-20240406162617244

直接修改配置文件就可以实现对象的替换,在以后修改实现对象的时候就不需要修改java代码,可以修改配置文件来实现。

Spring 配置

1、别名

使用 alias 标签可以给当前创建的bean创建一个别名,也就意味着可以通过原来的bean id获取对象,现在还可以通过别名也获取对象;

给user对象配置别名

<bean name="user" class="com.huaijiuwang.pojo.User" >
    <constructor-arg name="dataSources" value="怀旧" />
</bean>

<!-- 配置别名 -->
<alias name="user" alias="user1" />

使用测试:

// 参数写当前创建的配置文件的全名
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");


User user = (User) context.getBean("user");
System.out.println(user);


User user1 = (User) context.getBean("user1");
System.out.println(user1);

System.out.println(user == user1);

image-20240406165200231

通过测试发现我们可以通过两个不同的名称,都可以获取到user对象,并且他们指向的也是同一个地址。

2、Bean 的配置

image-20240406165521823

3、import 的配置

image-20240406165812730

依赖注入

1、构造器注入

就是前面讲过的那三种方式;

2、set 方式注入

image-20240406170234681

创建一个包含所有类型的复制实体类:

@Data
public class Address {
    private String address;
}
@Data
public class User {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String, String> card;
    private Set<String> games;
    private Properties info;
    private String wife;
}

测试第一种:字符串数据注入:

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">
    <bean id="user" class="com.huaijiuwang.pojo.User">
        <!-- 第一种字符串数据类型直接通过value注入 -->
        <property name="name" value="怀旧" />
    </bean>
</beans>

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

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

image-20240406171550399

第二种Bean注入 使用 ref:

<!-- 第二种Bean注入 使用 ref -->
<property name="address" ref="address" />

image-20240406171910904

第三种:数组注入:

<!-- 第三种数组注入 -->
<property name="books">
    <array>
        <value>书1</value>
        <value>书1</value>
        <value>书1</value>
    </array>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = (User) context.getBean("user");
System.out.println(Arrays.toString(user.getBooks()));

image-20240406172144345

第四种:list注入:

<!-- 第四种list注入 -->
<property name="hobbys">
    <list>
        <value>爱好1</value>
        <value>爱好2</value>
        <value>爱好3</value>
    </list>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = (User) context.getBean("user");
System.out.println(user.getHobbys());

image-20240406172329911

第五种:map注入:

<!-- 第五种map注入 -->
<property name="card">
    <map>
        <entry key="key1" value="value1" />
        <entry key="key2" value="value2" />
        <entry key="key3" value="value3" />
    </map>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = (User) context.getBean("user");
System.out.println(user.getCard());

image-20240406172524256

第六种:set注入:

 <!-- 第六种set注入 -->
<property name="games">
    <set>
        <value>游戏1</value>
        <value>游戏2</value>
        <value>游戏3</value>
    </set>
</property>

image-20240406172646302

第七种:null注入:

正常情况下数据不写是一个空字符串:如果想实现null注入就需要一下配置:

<!-- 第七种 null 注入 -->
<property name="wife">
    <null />
</property>

image-20240406172856493

第八种:properties注入:

<!-- 第八种 properties 注入 -->
<property name="info">
    <props>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </props>
</property>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = (User) context.getBean("user");
Properties info = user.getInfo();
System.out.println(info.getProperty("username"));
System.out.println(info.getProperty("password"));

image-20240406173117882

3、拓展方式注入

我们可以使用p命名空间和c命名空间进行注入;

使用前先导入需要的头命名空间:

<?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">

</beans>
// 需要写下面两个命名空间
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

p命名空间使用(set方式注入--替换property属性):

编写java类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
}
<?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">
    <bean id="user" class="com.huaijiuwang.pojo.User" p:name="怀旧" p:age="18" />
</beans>

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user", User.class);

System.out.println(user);

image-20240408094807686

c命名空间方式注入(其实就是通过构造器注入):

@Data
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        System.out.println("有参构造方法调用!");
        this.name = name;
        this.age = age;
    }
}
<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" />

image-20240408101820456

image-20240408101950843

4、Bean 的作用域

image-20240408102233517

Bean 的默认作用域就是单例的:

image-20240408102741946

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user1", User.class);
User user1 = context.getBean("user1", User.class);

System.out.println(user == user1);

image-20240408102406862

通过案例可以看到构造方法只呗调用了一次,而且是在没有获取bean的时候就已经加载了。并且两次获取的都是同一个对象地址;

我们可以显示的给作用域赋值:

<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" scope="singleton" />

image-20240408102529424

测试原型模式

修改配置:

<bean id="user1" class="com.huaijiuwang.pojo.User" c:age="15" c:name="怀旧2" scope="prototype" />
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

image-20240408102858375

有参构造没有被调用

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user1", User.class);
System.out.println(user);

User user1 = context.getBean("user1", User.class);
System.out.println(user1);

System.out.println(user == user1);

image-20240408102938300

调用了两次构造方法,并且两个对象是不同的两个地址;

image-20240408103055698

Bean 的自动装配

image-20240408103757103

image-20240408103807099

1、没有自动装配的情况

编写测试:

模拟场景,一个用户,拥有连个宠物,分别是猫和狗:

public class Cat {
    public void shout(){
        System.out.println("猫叫...");
    }
}
public class Dog {
    public void shout(){
        System.out.println("狗叫...");
    }
}
@Data
public class User {
    private String name;
    private Cat cat;
    private Dog dog;
}

编写xml:

<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User" p:name="怀旧"
      p:cat-ref="cat" p:dog-ref="dog" />

使用测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user", User.class);

user.getCat().shout();
user.getDog().shout();

image-20240408104742505

测试完成:

用上面的方式来实现十分麻烦,现在使用自动装配来实现:

2、通过配置实现自动装配

方式一(byName):

<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byName" />

image-20240408104848810

同样运行成功!

但是这边注意,我们使用autowire自动注入,里面的值为byName的时候:

  • 它会自动在容器上下文中查找,和自己对象set方法后面的值对应的Bean 的 id同名的引用自动装配赋值;

修改名称后测试:

<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byName" />

image-20240408105129173

运行报错!

方式二(byType):

  • 它会自动在容器上下文中查找,和自己对象属性类型相同的Bean然后自动装配赋值;
  • 对于这种方式,在全局必须唯一只有一个注入的类型的对象,不然就会报错

测试:

<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byType" />

image-20240408105424702

但是:

image-20240408105509561

因为byType是根据类型定义,所以就算前面定义的bean没有名称同样可以注入成功;

<bean class="com.huaijiuwang.pojo.Cat" />
<bean class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User" autowire="byType" />

image-20240408105621670

image-20240408105729878

3、使用注解实现自动装配

要使用注解需要知道:

  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
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context
		https://www.springframework.org/schema/context/spring-context.xsd">
</beans>
  1. 配置注解需要的支持(在配置文件中加入下面的即可)
<context:annotation-config/>

@Autowired注解使用

<?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
		https://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/>

    <bean id="cat" class="com.huaijiuwang.pojo.Cat" />
    <bean id="dog" class="com.huaijiuwang.pojo.Dog" />

    <bean id="user" class="com.huaijiuwang.pojo.User"/>
</beans>
@Data
public class User {
    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
}
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user", User.class);

user.getCat().shout();
user.getDog().shout();

image-20240408113059915

直接通过在属性上面添加注解就完成了注入;

也可以写在属性的set方法上面也可以,这边就不做演示了。

注意:因为这个自动注入是使用反射实现的所以我们注入的属性不需要有set方法也可以完成注入;

测试之前的方式,当 当前配置的bean没有名称:

<?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
		https://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/>

    <bean class="com.huaijiuwang.pojo.Cat" />
    <bean class="com.huaijiuwang.pojo.Dog" />

    <bean id="user" class="com.huaijiuwang.pojo.User"/>
</beans>

image-20240408113920199

同样能够自动注入,就代表@Autowired注解可以自动根据类型来装配

如果我们有多个bean的时候,我们也可以通过@Qualifier("cat1")来实现

<context:annotation-config/>

<bean id="cat1" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="cat2" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog2" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
    private String name;
    @Autowired
    @Qualifier("cat1")
    private Cat cat;
    @Autowired
    @Qualifier("dog1")
    private Dog dog;
}

image-20240408114156567

@Data
public class User {
    private String name;
    @Autowired
    @Qualifier("cat2")
    private Cat cat;
    @Autowired
    @Qualifier("dog2")
    private Dog dog;
}

image-20240408114216715

@Resource 注解使用

<bean id="cat" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
    private String name;

    @Resource
    private Cat cat;

    @Resource
    private Dog dog;
}

image-20240408142256957

<bean id="cat22" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog22" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User"/>
@Data
public class User {
    private String name;

    @Resource
    private Cat cat;

    @Resource
    private Dog dog;
}

image-20240408142325602

<bean class="com.huaijiuwang.pojo.Cat" />
<bean class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User"/>

image-20240408142346264

<bean id="cat1" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog1" class="com.huaijiuwang.pojo.Dog" />
<bean id="cat2" class="com.huaijiuwang.pojo.Cat" />
<bean id="dog2" class="com.huaijiuwang.pojo.Dog" />

<bean id="user" class="com.huaijiuwang.pojo.User"/>

image-20240408142415495

当通过byName和byType都找不到的时候就会报错了:

但是现在可以修改注解来实现通过Bean id注入

@Data
public class User {
    private String name;

    @Resource(name = "cat1")
    private Cat cat;

    @Resource(name = "dog1")
    private Dog dog;
}

image-20240408142536783

小结:

image-20240408142135144

使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了

image-20240408142811294

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

<?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
		https://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>
<!-- 指定要扫描的包,这个包下面的注解就会生效 -->
<context:component-scan base-package="com.huaijiuwang.pojo" />

1、Bean 的自动注入 (@Component):

首先需要配置注解扫码:

<context:component-scan base-package="com.huaijiuwang.pojo" />

创建实体类(在实体类上面加上@Component注解即可):

@Data
// 等价于:<bean id="user" class="com.huaijiuwang.pojo.User" />
@Component
public class User {
    private String name = "怀旧";
}

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user", User.class);

System.out.println(user);

image-20240408143506809

2、属性值的注入(@Value注解)

这个注解可以放在属性或者属性的set方法上

@Data
@Component
public class User {
    // 等价于: <property name="name" value="怀旧" />
    @Value("怀旧")
    private String name;
}

image-20240408143833387

3、衍生注解

@Component 有几个衍生的注解,我们在web开发中,会按照mvc三层架构分层!

  • dao :@Repository
  • service :@Service
  • controller :@Contrlooer

这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean!

4、自动装配

就是上面讲到的所有的自动注入属性值的那几个注解!

image-20240408145930636

因为每个包下面都有类;所以我们的注解扫描就需要配置到每一个类:

<context:component-scan base-package="com.huaijiuwang" />

User.java

@Data
@Component
public class User {
    @Value("怀旧")
    private String name;
}

UserDao.java

@Repository
public class UserDao {
    @Autowired
    private User user;

    public User getUser(){
        return this.user;
    }
}

UserService.java

@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public User getUser(){
        return this.userDao.getUser();
    }
}

UserController.java

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void showUser(){
        System.out.println(this.userService.getUser());
    }
}

测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserController userController = context.getBean("userController", UserController.class);
userController.showUser();

image-20240408150317032

5、作用域

@Scope 注解:和配置中编写的一样可以设定bean的作用域,默认还是singleton单例模式:

@Data
@Component
// 等价于:<bean id="user" class="com.huaijiuwang.pojo.User" scope="singleton" />
@Scope("singleton")
public class User {
    @Value("怀旧")
    private String name;
}

测试多例模式:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

User user = context.getBean("user", User.class);

User user1 = context.getBean("user", User.class);

System.out.println(user == user1);

image-20240408144741234

6、小结

image-20240408150510467

使用 Java 的方式配置 Spring

完全通过java来配置Spring,首先就可以删除所有的xml配置文件:

1.创建一个配置类,用来代替.xml文件

image-20240408151905282

1、@Configuration

@Configuration
public class MyConfig {
}

在代码中添加@Configuration注解,指定当前的类是一个配置类---.xml文件

image-20240408152029751

这个注解本身还继承了@Component注解,说明这个注解本身就是一个bean

2、@Bean

编写一个实体类用于测试:

@Data
public class User {
    private String name;
}

我们创建的这个类,没有添加@Component注解,说明当前的实体类没有被加载到Spring的容器中托管,我们现在就可以通过配置类来实现,我们之前的注册Bean实现:

@Configuration
public class MyConfig {
	
    // 这个必须写,指定当前的返回值就是当前获取的Bean实例
    @Bean
    public User getUser(){
        User user = new User();
        user.setName("通过配置类注册bean");

        return user;
    }
}

使用测试:

因为现在我们使用的是配置类,所以就不能使用之前的new ClassPathXmlApplicationContext() 这个来获取context对象了:

image-20240408152627574

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("getUser", User.class);

System.out.println(user);

image-20240408152844682

成功获取bean的对象

在获取bean的时候,我们的context.getBean("getUser", User.class); getbean的名称是需要指定注册@Bean的方法名来确定的

修改bean名称就会报错:

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("user", User.class);

System.out.println(user);

image-20240408153511306

测试获取的是否是同一个对象

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("getUser", User.class);
User user1 = context.getBean("getUser", User.class);

System.out.println(user == user1);

image-20240408152942696

通过输出可以看出获取到的是同一个对象:

我们现在就需要将当前的属性改为多例模式:

@Bean
@Scope("prototype")
public User getUser(){
    User user = new User();
    user.setName("通过配置类注册bean");

    return user;
}

image-20240408153127339

我们bean配置就可以直接在这边实现了!

3、@Import

在正常的xml配置中,可能遇到多个.xml文件,这个时候我们之前的做法是通过import标签来导入其他的配置文件进行汇众:现在我们可以通过注解的方式来实现:

例如现在又创建了一个配置类MyConfig1

@Configuration
public class MyConfig1 {

    @Bean
    public User user1(){
        User user = new User();
        user.setName("通过配置类1注册bean");

        return user;
    }
}

现在我们想使用user1这个bean,我们还是通过之前的代码获取

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("user1", User.class);

System.out.println(user);

image-20240408153812677

会报错,因为加载的不是我们配置user1的配置类,修改配置类

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig1.class);

User user = context.getBean("user1", User.class);

System.out.println(user);

image-20240408154002279

但是这样以后,我们配置的MyConfig的bean又无法加载了

所以现在就需要让两个配置类进行合并:使用@Import注解来导入其他配置

@Configuration
@Import(MyConfig1.class)
public class MyConfig {

    @Bean
    public User getUser(){
        User user = new User();
        user.setName("通过配置类注册bean");

        return user;
    }
}

现在测试:

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("getUser", User.class);
User user1 = context.getBean("user1", User.class);

System.out.println(user);
System.out.println(user1);

image-20240408154145918

两个地方的bean都可以被加载到;

4、@ComponentScan

在配置xml的时候我们可以配置宝的扫描,让其他的包同样可以使用注解,现在我们也可以通过在配置类添加注解来实现:

@Configuration
@Import(MyConfig1.class)
@ComponentScan("com.huaijiuwang.pojo")
public class MyConfig {
}

修改实体类;删除配置中注册的bean

@Data
@Component
public class User {
    @Value("通过注解注入值(配置注解包扫描)....")
    private String name;
}

测试:

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

User user = context.getBean("user", User.class);

System.out.println(user);

image-20240408155028487

代理模式

image-20240408160057578

1、静态代理

模拟我们吃饭:

在我们吃饭的过程中,我们需要先有饭,然后我们在吃饭,吃完饭之后别人来洗碗:

在上面的案例中,我们就是一个被代理的对象

代码步骤:

1.接口

public interface Eat {
    void eat();
}

2.真实角色(我,去吃饭)

public class User implements Eat{
    @Override
    public void eat() {
        System.out.println("我开始吃饭了!");
    }
}

3.代理角色(实现做饭,提供我可以吃饭,洗碗)

public class AgentUser implements Eat{
    // 被代理的角色(我)
    private User user;

    public AgentUser(User user) {
        this.user = user;
    }

    @Override
    public void eat() {
        // 在用户吃饭前,需要做饭
        this.before();

        // 让用户来吃饭了
        this.user.eat();

        // 用户吃完饭,洗碗
        this.after();
    }

    private void before(){
        System.out.println("开始做饭!!");
    }

    private void after(){
        System.out.println("开始洗碗!!");
    }
}

4.测试:

User user = new User();

AgentUser agentUser = new AgentUser(user);

agentUser.eat();

image-20240408162022245

image-20240408161153008

image-20240408161108476

2、动态代理

image-20240408163020242

需要用到两个类:Proxy: 代理, InvocationHandler: 调用处理程序

实现步骤:

1.创建实现动态代理的类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyInvocationHandler implements InvocationHandler {
    // 需要被代理的对象
    private Object target;

    // 需要被代理的对象,初始化就需要构造出来
    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    // 生成得到的代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    // 处理代理类对象,并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法执行前可以调用方法
        before();

        // 执行方法,并获得返回值
        Object result = method.invoke(target, args);

        // 方法执行后可以调用方法
        after();

        return result;
    }

    private void before(){
        System.out.println("开始做饭!!");
    }

    private void after(){
        System.out.println("开始洗碗!!");
    }
}

被代理的对象:

public class User implements Eat{
    @Override
    public void eat() {
        System.out.println("我开始吃饭了!");
    }
}

使用测试:

// 创建被代理对象
User user = new User();

// 创建 生成代理类的实力,并传入需要被代理的类的对象
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(user);

// 获取真实的代理类对象
Eat eat = (Eat) myInvocationHandler.getProxy();

// 执行代理后的方法
eat.eat();

image-20240408165329234

image-20240408165446565

AOP (面相切面编程)讲解

1、什么是 AOP

image-20240408165607055

image-20240408165557790

2、AOP 在 Spring 中的作用

image-20240408165800144

image-20240408165912248

image-20240408165925141

3、使用 Spring 实现 AOP

1.确保当前有AOP的包

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

image-20240408174011662

2.创建一个业务,模拟一个service

image-20240408171124047

UserService.java

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

UserServiceImpl.java

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("添加一个用户...");
    }

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

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

    @Override
    public void select() {
        System.out.println("查询一个用户...");
    }
}

3.创建aop代理执行前后的类

image-20240408171605890

MyBefore.java

// 配置被代理对象执行前
public class MyBefore implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() + " 类 " + method.getName() + " 方法被执行了!");
    }
}

MyAfter.java

// 配置被代理对象执行后
public class MyAfter implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(method.getName() + " 方法执行完毕了!");
    }
}

创建被代理对象bean 使用.xml文件配置

<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl" />
    <bean id="myBefore" class="com.huaijiuwang.aop.MyBefore" />
    <bean id="myAfter" class="com.huaijiuwang.aop.MyAfter" />

配置aop

配置规则:

在面向切面编程(AOP)中,切入点(Pointcut)用于定义在哪些方法或代码段上应该应用切面的逻辑。切入点使用表达式来匹配目标方法的签名和执行位置。

在Spring AOP 中,常用的切入点表达式是基于方法的 execution 表达式。execution 表达式由访问修饰符、返回类型、类名、方法名和参数列表组成,具体格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

其中,各个部分的含义如下:

modifiers-pattern(可选):指定方法的访问修饰符,如 public、private 等。 ret-type-pattern:指定方法的返回类型,如 int、void 等。使用通配符 * 可表示任意返回类型。 declaring-type-pattern(可选):指定方法所属的类名或包名。例如,com.example.Service 表示匹配 com.example 包下的所有以 “Service” 结尾的类。 name-pattern:指定方法名,可以使用通配符 * 表示任意方法名,如 get 表示以 “get” 开头的方法。 param-pattern:指定方法的参数列表。例如,(String, *) 表示第一个参数为 String 类型,第二个参数为任意类型。 throws-pattern(可选):指定方法可能抛出的异常。

<aop:config>
    <!-- 配置当前aop需要让那些方法进行代理 这里配置的就是所有修饰的方法 并且是UserServiceImpl下任意参数所有的方法
         id指的是一个标识,用来标识当前这个配置路径
    -->
    <aop:pointcut id="pointcut" expression="execution(* com.huaijiuwang.service.UserServiceImpl.*(..))"/>

    <!-- 配置切入的bean(就是执行前后调用的方法生效在当前id对应到的指向的代理的位置) -->
    <aop:advisor advice-ref="myBefore" pointcut-ref="pointcut" />
    <aop:advisor advice-ref="myAfter" pointcut-ref="pointcut" />
        
</aop:config>

使用测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserService userService = context.getBean("userService", UserService.class);

userService.add();
userService.update();
userService.delete();
userService.select();

image-20240408174046970

配置aop方式二(自定义类实现):

先自己编写一个类:

public class PointCat {
    public void before() {
        System.out.println("方法执行前调用.......");
    }

    public void after() {
        System.out.println("方法执行后调用.......");
    }
}

然后直接编写配置

<bean id="userService" class="com.huaijiuwang.service.UserServiceImpl" />

<bean id="pointCat" class="com.huaijiuwang.aop.PointCat" />

<aop:config>
    <!-- 自定义切面 ref要应用的类 -->
    <aop:aspect ref="pointCat">
        <!-- 切入点 -->
        <aop:pointcut id="pointcut" expression="execution(* com.huaijiuwang.service.UserServiceImpl.*(..))"/>
        <!-- 通知 -->
        <aop:before method="before" pointcut-ref="pointcut" />
        <aop:after method="after" pointcut-ref="pointcut" />
    </aop:aspect>
</aop:config>

测试运行:

image-20240408203807645

使用注解方式实现AOP:

使用注解 @Aspect 标识一个类为切面

// 标注类是一个切面
@Aspect
public class AnnotationPointCut {

    // 方法执行前
    @Before("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前...........");
    }

    // 方法执行后
    @After("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后...........");
    }
}

编写配置

<!-- 开启注解支持 -->
<bean id="annotationPointCut" class="com.huaijiuwang.aop.AnnotationPointCut" />
<aop:aspectj-autoproxy/>

运行测试:

image-20240408204618372

使用纯配置完成AOP

编写MyConfig配置类

@Configuration // 声明这是个配置类
@ComponentScan("com.huaijiuwang") // 扫描宝,可以使用spring注解
@EnableAspectJAutoProxy // 配置支持aop注解
public class MyConfig {
}

配置aop切面

// 标注类是一个切面
@Aspect
@Component
public class AnnotationPointCut {

    // 方法执行前
    @Before("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前...........");
    }

    // 方法执行后
    @After("execution(* com.huaijiuwang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后...........");
    }
}

注册service到spring容器中

@Service
public class UserServiceImpl implements UserService{

测试:

ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);

UserService userServiceImpl = context.getBean("userServiceImpl", UserService.class);
userServiceImpl.add();

image-20240408205733425

Spring 整合 Mybatis

导入需要的包:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.23</version> <!-- 选择与Java 8兼容的Spring版本 -->
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.30</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.7</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.10</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.23</version>
    </dependency>
</dependencies>

1、测试运行 Mybatis 程序

1.数据库表创建

-- 创建一个数据库
CREATE DATABASE `mybatis`;

-- 切换到创建的数据库
USE `mybatis`;

-- 创建一张表
CREATE TABLE `user`(
    `id` INT NOT NULL PRIMARY KEY,
    `name` VARCHAR(20),
    `password` VARCHAR(20)
)ENGINE=INNODB DEFAULT CHARSET=utf8;

-- 插入几条数据
INSERT INTO `user`(`id`, `name`, `password`)
VALUES(1, '怀旧', '123456'),
(2, '小旧', '654321'),
(3, '小旧', 'root');

-- 查询当前数据
SELECT * FROM `user`;

2.创建编写需要的.xml配置文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置类别名 -->
    <typeAliases>
        <package name="com.huaijiuwang.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8&amp;serverTimezone=UTC" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
</configuration>

3.编写实体类

@Data
public class User {
    private int id;
    private String name;
    private String password;
}

4.编写接口

public interface UserMapper {
    // 查询所有用户
    List<User> getUserList();
}

5.注册mapper到xml中

<mappers>
    <mapper resource="mapper/UserMapper.xml" />
</mappers>

6.编写Mapper.xml文件

<?xml version="1.0" encoding="UTF8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huaijiuwang.mapper.UserMapper">
    <select id="getUserList" resultType="com.huaijiuwang.pojo.User">
        select * from user
    </select>

</mapper>

6.测试运行

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

System.out.println(userMapper.getUserList());

image-20240408212044191

查询数据成功

2、通过Spring整合Mybatis 方式一

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
</beans>

2.配置数据库的数据源

<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8&amp;serverTimezone=UTC" />
    <property name="username" value="root" />
    <property name="password" value="123456" />
</bean>

3.配置Mybatis配置

<!-- 配置Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    <property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
</bean>

4.配置装载sqlSessionFactory

<!-- 配置Mybatis链接sqlSession -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

5.配置UserMapperImpl类(用来获取数据)

public class UserMapperImpl implements UserMapper{
    // 让spring注入,需要的sqlSession对象(就是配置的SqlSessionTemplate对象)
    private SqlSessionTemplate sqlSessionTemplate;

    // 通过构造方法注入
    public UserMapperImpl(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<User> getUserList() {
        // 返回实际的数据(建议写一行就行)
        return sqlSessionTemplate.getMapper(UserMapper.class).getUserList();
    }
}

6.将UserMapperImpl注册到spring容器

<!-- 注册UserMapperImpl对象 -->
<bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
    <constructor-arg name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
</bean>

7.测试运行:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);

System.out.println(userMapper.getUserList());

image-20240409091514444

优化:

将mybatis的配置区分开,作为一个新的模版,谁都可以套用:

创建一个文件mybatis-spring.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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8&amp;serverTimezone=UTC" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>

    <!-- 配置Mybatis配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
        <property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
    </bean>

    <!-- 配置Mybatis链接sqlSession -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
</beans>

在applicationContext.xml中引入配置即可:

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

    <!-- 引入mybatis的配置 -->
    <import resource="mybatis-spring.xml" />

    <!-- 注册UserMapperImpl对象 -->
    <bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
        <constructor-arg name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    </bean>
</beans>

测试运行:

image-20240409091919496

3、整合 Mybatis 方式二

修改实现maper类

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

    @Override
    public List<User> getUserList() {
        return getSqlSession().getMapper(UserMapper.class).getUserList();
    }
}

简化配置,

<!-- 配置数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8&amp;serverTimezone=UTC" />
    <property name="username" value="root" />
    <property name="password" value="123456" />
</bean>

<!-- 配置Mybatis配置 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    <property name="typeAliases" value="com.huaijiuwang.pojo.User"/>
</bean>

<!-- 注册UserMapperImpl对象 -->
<bean id="userMapper" class="com.huaijiuwang.mapper.UserMapperImpl">
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

从配置文件中,可以看出来我们少了一步获取SqlSessionTemplate步骤

测试运行:

image-20240409093141280

声明式事务

1、什么是事务

image-20240409093437565

image-20240409094907791

2、事务场景测试

模拟一组需要执行的事务情况,

添加一个用户后立马删除这个用户,需要同时执行:

1.编写接口

// 添加一个用户
int addUser(User user);

// 删除一个用户
int deleteUserById(int id);

2.编写mapper.xml

<insert id="addUser" parameterType="user">
    insert into user values(#{id}, #{name}, #{password})
</insert>

<delete id="deleteUserById" parameterType="int">
    delete from user where id = #{id}
</delete>

3.实现具体的接口

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{

    @Override
    public List<User> getUserList() {

        getSqlSession().getMapper(UserMapper.class).addUser(user)
        getSqlSession().getMapper(UserMapper.class).deleteUserById(id)

        return getSqlSession().getMapper(UserMapper.class).getUserList();
    }

    @Override
    public int addUser(User user) {
        return 0;
    }

    @Override
    public int deleteUserById(int id) {
        return 0;
    }
}

4.测试:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserMapper userMapper = context.getBean("userMapper", UserMapper.class);

userMapper.getUserList().forEach(System.out::println);

image-20240409094657672

添加后完成删除;

现在模拟异常情况:

修改删除语句:

<delete id="deleteUserById" parameterType="int">
    delete 1 from user where id = #{id}
</delete>

运行测试:

image-20240409094754277

运行报错,查看数据:

image-20240409100457892

数据被添加进去了,不符合需求,现在就需要使用spring来控制事务了;

3、通过Spring配置事务

image-20240409100823447

1.配置声明式事务

<!-- 配置声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

2.结合aop实现事务的植入

<!-- 结合aop实现事务的植入 -->
<!-- 配置事务的通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!-- 给那些方法配置事务 -->
    <tx:attributes>
        <!-- name:配置事务管理哪一类方法  propagation: 配置事务的传播特性 -->
        <tx:method name="add" propagation="REQUIRED" />
        <tx:method name="insert" propagation="REQUIRED" />
        <!-- * 代表所有方法 -->
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

3.配置事务的切入

<!-- 配置事务的切入 -->
<aop:config>
    <aop:pointcut id="txPointcut" expression="execution(* com.huaijiuwang.mapper.UserMapperImpl.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>

4.测试(原有的代码没有做任何修改):

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

UserMapper userMapper = context.getBean("userMapper", UserMapper.class);

userMapper.getUserList().forEach(System.out::println);

image-20240409100701926

运行依然报错:

image-20240409100712474

查看数据库数据,没有发生改变,说明事务配置成功!

image-20240409100905731

  • 平台作者:怀旧(联系作者)
  • QQ:444915368
  • 邮箱:444915368@qq.com
  • 电话:17623747368
  • 评论

    登录后才可以进行评论哦!

    回到顶部 留言