Spring5

简介

代码:https://github.com/Donkequan/Spring-Study

spring理念:是现有的技术更加容易使用,本身是一个大杂烩。

  • SSH:Struct2 + Spring + Hibernate
  • SSM: SpringMVC + Spring + Mybatis

官网: https://spring.io/projects/spring-framework#overview

官方下载: https://repo.spring.io/release/org/springframework/spring/

GitHub: https://github.com/spring-projects/spring-framework

Maven

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

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.3.RELEASE</version>
</dependency>
  • spring是开源的免费的容器。
  • spring是一个轻量级的,非入侵式的。
  • 控制反转(IOC),面向切面编程 (AOP)。
  • 支持事务处理,对框架整合的支持。

总结:spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。

组成

在这里插入图片描述

拓展

Spring Boot与Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
  • Spring Cloud是基于Spring Boot实现的;
  • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
  • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , SpringCloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
  • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

IOC理论

我们先用我们原来的方式写一段代码 .

1、先写一个UserDao接口

public interface UserDao {
   public void getUser();
}

2、再去写Dao的实现类

public class UserDaoImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("获取用户数据");
  }
}

3、然后去写UserService的接口

public interface UserService {
   public void getUser();
}

4、最后写Service的实现类

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

5、测试一下

@Test
public void test(){
   UserService service = new UserServiceImpl();
   service.getUser();
}

这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

把Userdao的实现类增加一个 .

public class UserDaoMySqlImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("MySql获取用户数据");
  }
}

紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoMySqlImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

在假设, 我们再增加一个Userdao的实现类 .

public class UserDaoOracleImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Oracle获取用户数据");
  }
}

那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

那我们如何去解决呢 ?

我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .

public class UserServiceImpl implements UserService {
   private UserDao userDao;
// 利用set实现
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

现在去我们的测试类里 , 进行测试 ;

@Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   service.setUserDao( new UserDaoMySqlImpl() );
   service.getUser();
   //那我们现在又想用Oracle去实现呢
   service.setUserDao( new UserDaoOracleImpl() );
   service.getUser();
}

大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

HelloSpring

导入Jar包

注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .

org.springframework spring-webmvc 5.1.10.RELEASE 编写代码

1、编写一个Hello实体类

public class Hello {
   private String name;

   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("Hello,"+ name );
  }
}

2、编写我们的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就是java对象 , 由Spring创建和管理-->
   <bean id="hello" class="com.kuang.pojo.Hello">
       <property name="name" value="Spring"/>
   </bean>

</beans>

3、我们可以去进行测试了 .

@Test
public void test(){
//解析beans.xml文件 , 生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);
//getBean : 参数即为spring配置文件中bean的id .
Hello hello = (Hello) context.getBean(“hello”);
hello.show();
}

思考

Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的

Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转 :

控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
依赖注入 : 就是利用set方法来进行注入的.

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

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

修改案例一

我们在案例一中, 新增一个Spring配置文件beans.xml

<?xml version="1.0" encoding="UTF-8"?>

测试!

@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext(“beans.xml”);
UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean(“ServiceImpl”);
serviceImpl.getUser();
}
OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !

IOC创建对象方式

通过无参构造方法来创建

1、User.java

public class User {

   private String name;

   public User() {
       System.out.println("user无参构造方法");
  }

   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("name="+ name );
  }

}

2、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="user" class="com.kuang.pojo.User">
       <property name="name" value="kuangshen"/>
   </bean>

</beans>

3、测试类

@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //在执行getBean的时候, user已经创建好了 , 通过无参构造
   User user = (User) context.getBean("user");
   //调用对象的方法 .
   user.show();
}

结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

通过有参构造方法来创建

1、UserT . java

public class UserT {

   private String name;

   public UserT(String name) {
       this.name = name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("name="+ name );
  }

}

2、beans.xml 有三种方式编写

<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- index指构造方法 , 下标从0开始 -->
   <constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- name指参数名 -->
   <constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>

3、测试

@Test
public void testT(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserT user = (UserT) context.getBean("userT");
   user.show();
}

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

Spring配置

别名

alias 设置别名 , 为bean设置别名 , 可以设置多个别名

<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>

Bean的配置

<!--bean就是java对象,由Spring创建和管理-->

<!--
   id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
   如果配置id,又配置了name,那么name是别名
   name可以设置多个别名,可以用逗号,分号,空格隔开
   如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;

class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>

import

团队的合作通过import来实现 .

<import resource="{path}/beans.xml"/>

依赖注入(DI)

  • 依赖注入(Dependency Injection,DI)。
  • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .

构造器注入

我们在之前的案例已经讲过了

Set 注入 (重点)

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

测试pojo类 :

Address.java

 public class Address {
 
     private String address;
 
     public String getAddress() {
         return address;
    }
 
     public void setAddress(String address) {
         this.address = address;
    }
 }

Student.java

package com.kuang.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 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;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAddress(Address address) {
         this.address = address;
    }
 
     public void setBooks(String[] books) {
         this.books = books;
    }
 
     public void setHobbys(List<String> hobbys) {
         this.hobbys = hobbys;
    }
 
     public void setCard(Map<String, String> card) {
         this.card = card;
    }
 
     public void setGames(Set<String> games) {
         this.games = games;
    }
 
     public void setWife(String wife) {
         this.wife = wife;
    }
 
     public void setInfo(Properties info) {
         this.info = info;
    }
 
     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n爱好:"+hobbys);
 
         System.out.println("card:"+card);
 
         System.out.println("games:"+games);
 
         System.out.println("wife:"+wife);
 
         System.out.println("info:"+info);
 
    }
 }

1、常量注入

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
 </bean>

测试:

@Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 
     Student student = (Student) context.getBean("student");
 
     System.out.println(student.getName());
 
 }

2、Bean注入

注意点:这里的值是一个引用,ref

 <bean id="addr" 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="addr"/>
 </bean>

3、数组注入

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="小明"/>
     <property name="address" ref="addr"/>
     <property name="books">
         <array>
             <value>西游记</value>
             <value>红楼梦</value>
             <value>水浒传</value>
         </array>
     </property>
 </bean>

4、List注入

<property name="hobbys">
     <list>
         <value>听歌</value>
         <value>看电影</value>
         <value>爬山</value>
     </list>
 </property>

5、Map注入

 <property name="card">
     <map>
         <entry key="中国邮政" value="456456456465456"/>
         <entry key="建设" value="1456682255511"/>
     </map>
 </property>

6、set注入

 <property name="games">
     <set>
         <value>LOL</value>
         <value>BOB</value>
         <value>COC</value>
     </set>
 </property>

7、Null注入

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

8、Properties注入

<property name="info">
     <props>
         <prop key="学号">20190604</prop>
         <prop key="性别">男</prop>
         <prop key="姓名">小明</prop>
     </props>
 </property>

测试结果:

在这里插入图片描述

p命名和c命名注入

User.java :【注意:这里没有有参构造器!】

 public class User {
     private String name;
     private int age;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAge(int age) {
         this.age = age;
    }
 
     @Override
     public String toString() {
         return "User{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
    }
 }

1、P命名空间注入 : 需要在头文件中加入约束文件

导入约束 : xmlns:p=“http://www.springframework.org/schema/p”

 <!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
 <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>

2、c 命名空间注入 : 需要在头文件中加入约束文件

导入约束 : xmlns:c=“http://www.springframework.org/schema/c”

 <!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
 <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>

发现问题:爆红了,刚才我们没有写有参构造!

解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!

测试代码:

 @Test
 public void test02(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     System.out.println(user);
 }

Bean的作用域

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .

几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

Singleton

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

测试

@Test
 public void test03(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     User user2 = (User) context.getBean("user");
     System.out.println(user==user2);
 }

Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

 <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/> 

或者

 <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>

Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

自动装配

自动装配是使用spring满足bean依赖的一种方法

spring会在应用上下文中为某个bean寻找其依赖的bean。

Spring中bean有三种装配机制,分别是:

  • 在xml中显式配置;
  • 在java中显式配置;
  • 隐式的bean发现机制和自动装配。

这里我们主要讲第三种:自动化的装配bean。

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  • 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  • 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

推荐不使用自动装配xml配置 , 而使用注解 .

测试环境搭建

1、新建一个项目

2、新建两个实体类,Cat Dog 都有一个叫的方法

public class Cat {
   public void shout() {
       System.out.println("miao~");
  }
}
public class Dog {
   public void shout() {
       System.out.println("wang~");
  }
}

3、新建一个用户类 User

public class User {
   private Cat cat;
   private Dog dog;
   private String str;
}

4、编写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">

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

   <bean id="user" class="com.kuang.pojo.User">
       <property name="cat" ref="cat"/>
       <property name="dog" ref="dog"/>
       <property name="str" value="qinjiang"/>
   </bean>
</beans>

5、测试

public class MyTest {
   @Test
   public void testMethodAutowire() {
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       User user = (User) context.getBean("user");
       user.getCat().shout();
       user.getDog().shout();
  }
}

结果正常输出,环境OK

byName

autowire byName (按名称自动装配)

由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

采用自动装配将避免这些错误,并且使配置简单化。

测试:

1、修改bean配置,增加一个属性 autowire=“byName”

<bean id="user" class="com.kuang.pojo.User" autowire="byName">
   <property name="str" value="qinjiang"/>
</bean>

2、再次测试,结果依旧成功输出!

3、我们将 cat 的bean id修改为 catXXX

4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

小结:

  • 当一个bean节点带有 autowire byName的属性时。
  • 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
  • 去spring容器中寻找是否有此字符串名称id的对象。
  • 如果有,就取出注入;如果没有,就报空指针异常。

byType

autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
NoUniqueBeanDefinitionException
测试:

1、将user的bean配置修改一下 : autowire=“byType”

2、测试,正常输出

3、在注册一个cat 的bean对象!

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

<bean id="user" class="com.kuang.pojo.User" autowire="byType">
   <property name="str" value="qinjiang"/>
</bean>

4、测试,报错:NoUniqueBeanDefinitionException

5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

这就是按照类型自动装配!

使用注解实现自动装配

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"
      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></context:annotation-config>
	
</beans>

@Autowired

默认是byType方式,如果匹配不上,就会byName

在属性上个使用,也可以在set上使用

我们可以不用编写set方法了,前提是自动装配的属性在Spring容器里,且要符合ByName 自动装配

public class People {
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;
}

@Nullable 字段标记了这个注解,说明该字段可以为空

public name(@Nullable String name){
}

如果定义了Autowire的require属性为false,说明这个对象可以为null,否则不允许为空(false表示找不到装配,不抛出异常)

@Autowired+@Qualifier

@Autowired不能唯一装配时,需要@Autowired+@Qualifier

如果@Autowired自动装配环境比较复杂。自动装配无法通过一个注解完成的时候,可以使用@Qualifier(value = “dog”)去配合使用,指定一个唯一的id对象

public class People {
    @Autowired
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog")
    private Dog dog;
    private String name;
}

如果xml文件中同一个对象被多个bean使用,Autowired无法按类型找到,可以用@Qualifier指定id查找
Autowired是byType,@Autowired+@Qualifier = byType || byName

@Resource

默认是byName方式,如果匹配不上,就会byType

public class People {
    Resource(name="cat")
    private Cat cat;
    Resource(name="dog")
    private Dog dog;
    private String name;
}

区别:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上 @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byname的方式实现

来自弹幕大神:

@Autowired:
当注入在IoC容器中该类型只有一个时,就通过byType进行装配
当注入容器存在多个同一类型的对象时,就是根据byName进行装配

@Autowired默认是按Bytype @Resources默认是按ByName

按属性名或类型二者满足其中一个就可以,因为多个同类型下,存在一个名字相同也装配成功

@autowired会按bytype, byname找一遍 都没才需要qualifier

一般用autowired,但resource功能会强大一点

autowired是先byteType,如果唯一則注入,否则byName查找。resource是先byname,不符合再继续byType

使用注解开发

在spring4之后,使用注解开发,必须要保证aop包的导入
在这里插入图片描述
使用注解需要导入contex的约束

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

bean

弹幕评论:
有了< context:component-scan>,另一个< context:annotation-config/>标签可以移除掉,因为已经被包含进去了。

<!--指定要扫描的包,这个包下面的注解才会生效
	别只扫一个com.kuang.pojo包--> 
<context:component-scan base-package="com.kuang"/> 
<context:annotation-config/>
//@Component 组件
//等价于<bean id="user" classs"pojo.User"/> 
@Component
public class User {  
     public String name ="秦疆";
}

属性如何注入@value

@Component
public class User { 
    //相当于<property name="name" value="kuangshen"/> 
    @value("kuangshen") 
    public String name; 
    
    //也可以放在set方法上面
    //@value("kuangshen")
    public void setName(String name) { 
        this.name = name; 
    }
}

衍生的注解

@Component有几个衍生注解,会按照web开发中,mvc架构中分层。

  • dao (@Repository)
  • service(@Service)
  • controller(@Controller)
    这四个注解的功能是一样的,都是代表将某个类注册到容器中

自动装配

  • @Autowired:默认是byType方式,如果匹配不上,就会byName
  • @Nullable:字段标记了这个注解,说明该字段可以为空
  • @Resource:默认是byName方式,如果匹配不上,就会byType

作用域@scope

//原型模式prototype,单例模式singleton
//scope("prototype")相当于<bean scope="prototype"></bean>
@Component 
@scope("prototype")
public class User { 
    
    //相当于<property name="name" value="kuangshen"/> 
    @value("kuangshen") 
    public String name; 
    
    //也可以放在set方法上面
    @value("kuangshen")
    public void setName(String name) { 
        this.name = name; 
    }
}

小结

xml与注解:

  • xml更加万能,维护简单,适用于任何场合
  • 注解,不是自己的类使用不了,维护复杂

最佳实践:

  • xml用来管理bean
  • 注解只用来完成属性的注入
  • 要开启注解支持

来自弹幕大佬:

@Component是标注在一个类上的,作用是将被标注的类注册在spring容器中,将类的实例化交给spring管理,完成的是bean的注册
@Autowired是标注在类中的成员变量或方法上,完成的是bean的注入
当一个类Class A中需要一个B类型的变量时 在声明变量时加上@Autowired ,spring会在容器中寻找有没有被@Component注册过的类

使用Java的方式配置Spring

不使用Spring的xml配置,完全交给java来做!

Spring的一个子项目,在spring4之后它成为了核心功能
在这里插入图片描述
实体类:pojo的User.java

//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中 
@component 
public class User { 
    private String name;
    
    public String getName() { 
    	return name; 
    } 
    //属性注入值
    @value("QINJIANG')  
    public void setName(String name) { 
    	this.name = name; 
    } 
    @Override 
    public String toString() { 
        return "user{" + 
        "name='" + name + '\''+ 
        '}'; 
    } 
}

配置文件:config中的kuang.java

@Import(KuangConfig2.class),用@import来包含KuangConfig2.java
//这个也会Spring容器托管,注册到容器中,因为他本米就是一个@Component 
// @Configuration表这是一个配置类,就像我们之前看的beans.xml,类似于<beans>标签
@Configuration 
@componentScan("com.Kuang.pojo") //开启扫描
//@Import(KuangConfig2.class)
public class KuangConfig { 
    //注册一个bean , 就相当于我们之前写的一个bean 标签 
    //这个方法的名字,就相当于bean 标签中的 id 属性 ->getUser
    //这个方法的返同值,就相当于bean 标签中的class 属性 ->User
    
    //@Bean 
    public User getUser(){ 
    	return new User(); //就是返回要注入到bean的对象! 
    } 
}

测试类

public class MyTest { 
    public static void main(String[ ] args) { 
    //如果完全使用了配置类方式去做,我们就只能通过 Annotationconfig 上下文来获取容器,通过配置类的class对象加载! 
    ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.Class); //class对象
    User getUser =(User)context.getBean( "getUser"); //方法名getUser
    System.out.Println(getUser.getName()); 
    } 
}

会创建两个相同对象问题的说明:

弹幕总结 - -> @Bean是相当于< bean>标签创建的对象,而我们之前学的@Component是通过spring自动创建的这个被注解声明的对象,所以这里相当于有两个User对象被创建了。一个是bean标签创建的(@Bean),一个是通过扫描然后使用@Component,spring自动创建的User对象,所以这里去掉@Bean这些东西,然后开启扫描。之后在User头上用@Component即可达到spring自动创建User对象了

如此测试类就变成:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(XuConfig.class);
        User user = context.getBean("user", User.class);
        System.out.println(user.getName());
    }
}

来自弹幕大神

  • 要么使用@Bean,要么使用@Component和ComponentScan,两种效果一样
  • ComponentScan、@Component("pojo”) 这两个注解配合使用

代理模式

代理模式是SpringAOP的底层

分类:动态代理和静态代理
在这里插入图片描述

静态代理

在这里插入图片描述
代码步骤:
接口

package pojo;
public interface Host {
	public void rent();
}

真实角色

package pojo;
public class HostMaster implements Host{	
    
	public void rent() {
		System.out.println("房东要出租房子");
	}
}

代理角色

package pojo;
public class Proxy implements Host{

	public Host host;
	
	public Proxy() {
		
	}
	
	public Proxy(Host host) {
		super();
		this.host = host;
	}
	
	public void rent() {
		seeHouse();
		host.rent();
		fee();
		sign();
	}
	//看房
	public void seeHouse() {
		System.out.println("看房子");
	}
	//收费
	public void fee() {
		System.out.println("收中介费");
	}
	//合同
	public void sign() {
		System.out.println("签合同");
	}		
}

客户端访问代理角色

package holle4_proxy;

import pojo.Host;
import pojo.HostMaster;
import pojo.Proxy;

public class My {

	public static void main(String[] args) {
		//房东要出租房子
		Host host = new HostMaster();
		//中介帮房东出租房子,但也收取一定费用(增加一些房东不做的操作)
		Proxy proxy = new Proxy(host);
		//看不到房东,但通过代理,还是租到了房子
		proxy.rent();
		
	}
}

在这里插入图片描述

静态代理再理解

接口(要实现的功能)

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

真实角色

public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("add");
    }

    public void delete() {
        System.out.println("delete");
    }
}

代理角色

public class UserServiceProxy {
    private UserServiceImpl userService;
    public void setUserService(UserServiceImpl userService){
        this.userService=userService;
    }
    public void add(){
        log("add");
        userService.add();
    }

    public void delete(){
        log("delete");
        userService.delete();
    }
    public void log(String msg){
        System.out.println("调用"+msg+"方法");
    }
}

客户调用代理

public class Client {
    public static void main(String[] args) {
        UserServiceProxy proxy = new UserServiceProxy();
        UserServiceImpl userService = new UserServiceImpl();
        proxy.setUserService(userService);
        proxy.add();
        proxy.delete();
    }
}

AOP横向开发

在这里插入图片描述
也就是在不改变原有业务代码的基础上横向扩展功能,这就叫面向切面编程

动态代理

动态代理和静态角色一样,动态代理底层是反射机制

动态代理类是动态生成的,不是我们直接写好的!

动态代理(两大类):基于接口,基于类

  • 基于接口:JDK的动态代理【使用ing】
  • 基于类:cglib
  • java字节码实现:javasisit

了解两个类
1、Proxy:代理
2、InvocationHandler:调用处理程序

在这里插入图片描述

实例:

接口 Host.java

//接口
package pojo2;
public interface Host {
	public void rent();
	
}

接口Host实现类 HostMaster.java

//接口实现类
package pojo2;
public class HostMaster implements Host{	
	public void rent() {
		System.out.println("房东要租房子");
	}
}

代理角色的处理程序类 ProxyInvocationHandler.java

package pojo2;

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

///用这个类,自动生成代理
public class ProxyInvocationHandler implements InvocationHandler {

	// Foo f =(Foo) Proxy.NewProxyInstance(Foo. Class.GetClassLoader(),
	// new Class<?>[] { Foo.Class },
	// handler);

	// 被代理的接口
	public HostMaster hostMaster ;
	
	public void setHostMaster(HostMaster hostMaster) {
		this.hostMaster = hostMaster;
	}

	// 得到生成的代理类 
	public Object getProxy() {
		// newProxyInstance() -> 生成代理对象,就不用再写具体的代理类了
		// this.getClass().getClassLoader() -> 找到加载类的位置
		// hostMaster.getClass().getInterfaces() -> 代理的具体接口
		// this -> 代表了接口InvocationHandler的实现类ProxyInvocationHandler
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), hostMaster.getClass().getInterfaces(), this);


	// 处理代理实例并返回结果
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		seeHouse();
		// 动态代理的本质,就是使用反射机制实现的
        // invoke()执行它真正要执行的方法
		Object result = method.invoke(hostMaster, args);
		fee();
		return result;
	}

	public void seeHouse() {
		System.out.println("看房子");
	}

	public void fee() {
		System.out.println("收中介费");
	}

}

用户类 My2.java

package holle4_proxy;

import pojo2.Host;
import pojo2.Host2;
import pojo2.HostMaster;
import pojo2.ProxyInvocationHandler;

public class My2 {

	public static void main(String[] args) {
        
		//真实角色
		HostMaster hostMaster = new HostMaster();
        
		//代理角色,现在没有;用代理角色的处理程序来实现Host接口的调用
		ProxyInvocationHandler pih = new ProxyInvocationHandler();
        
        //pih -> HostMaster接口类 -> Host接口
		pih.setHostMaster(hostMaster);
        
		//获取newProxyInstance动态生成代理类
		Host proxy = (Host) pih.getProxy();
		
		proxy.rent();

	}
}

弹幕评论:
什么时候调用invoke方法的?
代理实例调用方法时invoke方法就会被调用,可以debug试试

万能代理类

///用这个类,自动生代理
public class ProxyInvocationHandler implements InvocationHandler {

	// 被代理的接口
	public Object target;

	public void setTarget(Object target) {
		this.target = target;
	}

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

	// 处理代理实例并返回结果
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 动态代理的本质,就是使用反射机制实现的
		// invoke()执行它真正要执行的方法
		Object result = method.invoke(target, args);
		return result;
	}

}

在这里插入图片描述

使用Spring实现AOP

导入jar包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>

方法一:使用原生spring接口

springAPI接口实现

applicationContext.xml

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

    <!--注册bean-->
    <bean id="userService" class="com.xwc.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.xwc.service.AfterLog"/>
    <bean id="beforeLog" class="com.xwc.service.BeforeLog"/>
	<!--方式一,使用原生Spring API接口-->
    <!--配置aop,还需要导入aop约束-->
    <aop:config>
        <!--切入点:expression:表达式,execution(要执行的位置)-->
        <aop:pointcut id="pointcut" expression="execution(* com.xwc.service.UserServiceImpl.*(..))"/>
        <!--UserServiceImpl.*(..) -》 UserServiceImpl类下的所以方法(参数)-->
        <!--执行环绕增加-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"></aop:advisor>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
        <!-- 环绕,在id="pointcut"的前后切入 -->
    </aop:config>

</beans>

execution(返回类型,类名,方法名(参数)) -> execution(* com.service.,(…))

UserService.java

package service;
public interface UserService {   
	    public void add() ;
	    public void delete() ;
	    public void query() ;
	    public void update();
}

UserService 的实现类 UserServiceImp.java

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 select() {
        System.out.println("查询一个用户");
    }
}

前置BeforeLog.java

package log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    //method:要执行的目标对象的方法
    //args:参数
    //target:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

后置AfterLog.java

public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为"+o);
    }
}

测试类MyTest

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }
}

方法二:自定义类实现AOP

applicationContext.xml

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

    <!--注册bean-->
    <bean id="userService" class="com.xwc.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.xwc.service.AfterLog"/>
    <bean id="beforeLog" class="com.xwc.service.BeforeLog"/>

    <bean id="diyPointCut" class="com.xwc.diy.DiyPointCut"></bean>
    
    <aop:config>
    <!--自定义切面-->
        <aop:aspect ref="diyPointCut">
        <!--切入点-->
            <aop:pointcut id="pointcut" expression="execution(* com.xwc.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
            <aop:after method="after" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
    </aop:config>

</beans>

DiyPointCut

public class DiyPointCut {
    public void before(){
        System.out.println("方法执行前");
    }
    public void after(){
        System.out.println("方法执行后");
    }
}

测试类MyTest

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }
}

方法三:使用注解实现

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://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="userService" class="com.xwc.service.UserServiceImpl"/>
    <bean id="annotationPointCut" class="com.xwc.diy.AnnotationPointCut"></bean>
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

AnnotationPointCut

@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.xwc.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前");
    }
    @After("execution(* com.xwc.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("方法执行后");
    }
    @Around("execution(* com.xwc.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前");
        System.out.println(joinPoint.getSignature());
        Object proceed = joinPoint.proceed();//执行方法
        System.out.println("环绕后");
    }
}

测试

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = context.getBean("userService",UserService.class);
        userService.add();
    }
}

输出结果:
在这里插入图片描述
AOP本质:在不影响原来业务的情况下,实现动态增强

mybatis-spring-方式一

步骤

  1. 编写数据源配置
  2. sqISessionFactory
  3. sqISessionTemplate(相当于sqISession)
  4. 需要给接口加实现类【new】
  5. 将自己写的实现类,注入到Spring中
  6. 测试!

先导入jar包

<dependencies>

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

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

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.7.RELEASE</version>
    </dependency>

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

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

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

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.12</version>
    </dependency>

</dependencies>
	
<!--在build中配置resources,来防止资源导出失败的问题-->
<!-- Maven解决静态资源过滤问题 -->
<build>
<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
</resources>
</build>

架构
在这里插入图片描述
编写顺序:
User -> UserMapper -> UserMapper.xml -> spring-dao.xml -> UserServiceImpl -> applicationContext.xml -> MyTest

pojo实体类 User

import lombok.Data;
@Data
public class User {
	private int id;
	private String name;
	private String pwd;
}

接口UserMapper

import java.util.List;
import pojo.User;
public interface UserMapper {
	public List<User> getUser();
}

UserMapperImpl

public class UserMapperImpl implements UserMapper {

    //我们的所有操作,在原来都使用sqlSession来执行,现在都使用SqlSessionTemplate;
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> getUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUser();
    }
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- 绑定接口 -->
<mapper namespace="com.xwc.Mapper.UserMapper">
    <select id="getUser" resultType="com.xwc.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="com.xwc.pojo"/>
    </typeAliases>
</configuration>

spring-dao.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://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="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=false&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="**********"/>
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:UserMapper.xml"/>
    </bean>

    <!-- sqlSessionTemplate 就是之前使用的:sqlsession -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!-- 只能使用构造器注入sqlSessionFactory 原因:它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <bean id="userMapper" class="com.xwc.Mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"></property>
    </bean>
</beans>

测试类

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");

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

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

mybatis-spring-方式二

UserServiceImpl2

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
    public List<User> getUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUser();
        //或者一句话:return getSqlSession().getMapper(UserMapper.class).getUser();
    }
}

spring-dao.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://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="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=false&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="xuweichi691122"/>
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:UserMapper.xml"/>
    </bean>
        <bean id="userMapper2" class="com.xwc.Mapper.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>

</beans>

测试

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");

        UserMapper userMapper = (UserMapper) context.getBean("userMapper2");

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

声明式事务

  • 把一组业务当成一个业务来做;要么都成功,要么都失败!
  • 事务在项目开发中,十分的重要,涉及到数据的一致性问题
  • 确保完整性和一致性

事务的ACID原则:
1、原子性
2、隔离性
3、一致性
4、持久性

Spring中的事务管理:
声明式事务:AOP
编程式事务:需要再代码中,进行事务管理

代码步骤:
pojo实体类 User

package pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
	private int id;
	private String name;
	private String pwd;
}

接口UserMapper

import java.util.List;
import org.apache.ibatis.annotations.Param;
import pojo.User;

public interface UserMapper {
	public List<User> getUser();
	
	public int insertUser(User user); 
	
	public int delUser(@Param("id") int id); 
}

UserMapperImpl2

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    public List<User> getUser() {
        User user = new User(10,"嘿嘿","哈哈");
        insertUser(user);
        delUser(5);
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUser();
        //或者return  getSqlSession().getMapper(UserMapper.class).getUser();
    }
    //插入
    public int insertUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).insertUser(user);
    }
    //删除
    public int delUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).delUser(id);
    }

}

UserMapper.xml

<mapper namespace="com.xwc.Mapper.UserMapper">
    <select id="getUser" resultType="com.xwc.pojo.User">
        select * from mybatis.user
    </select>
    <insert id="insertUser"  parameterType="user" >
        insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <delete id="delUser" parameterType="int">
	    <!-- deletes是故意写错的 -->
        deletes from mybatis.mybatis where id = #{id}
    </delete>
</mapper>

测试类

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");

        UserMapper userMapper = (UserMapper) context.getBean("userMapper2");

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

测试结果:
delete报错,但插入成功
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值