Spring5学习笔记

1.Spring

Spring官网:https://spring.io/projects/spring-framework

Spring下载地址:https://repo.spring.io/release/org/springframework/spring/

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

Maven依赖


<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-webmvcartifactId>
    <version>5.2.4.RELEASEversion>
dependency>

<dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-jdbcartifactId>
    <version>5.2.4.RELEASEversion>
dependency>

优点

  • spring是一个开源的免费的框架(容器)
  • spring是一个轻量级,非入侵式框架
  • 控制反转IOC 、面向切面编程AOP
  • 支持事务的处理,对框架整合的支持
    总结一句话:
    Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架

Spring七大模块
Spring5学习笔记_第1张图片

2.IOC理论推导

项目:spring_study
模块:spring_01_ioc01

来我们来回顾以下我们以前的程序
UserDao 接口
UserDaoImpl 实现类
UserService 接口
UserServiceImpl 实现类
最后测试
结构如下
Spring5学习笔记_第2张图片
上图可以看到 如果一个dao有多个实现类
UserServiceImpl中代码:

public class UserServiceImpl implements UserService{
    UserDao userDao = new UserDaoMysql();
    public void getUser() {
        userDao.getUser();
    }
}
如果今天我们用的是UserDaoMysql实现类 
明天项目改变,需要用到UserDaoOracle实现类
我们这时候就要回到UserServiceImpl中修改代码
UserDao userDao = new UserDaoOracle();
如果一个程序有十几二十个实现类,每次都要自己来手动改变代码吗?
每一次改动都要在源代码中动手脚,这样的程序不是一个合格的程序

这时候控制反转(IOC)就可以很好的解决此问题
UserServiceImpl代码:

public class UserServiceImpl implements UserService{
    private UserDao userDao ;

    //动态set注入,控制反转,将主动权给客户端,客户端需要哪个就指定哪个,
    // service通过客户端指定的需求去找
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }

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

测试代码

public class MyTest {
    public static void main(String[] args) {

        UserServiceImpl userService = new UserServiceImpl();
        //客户端指定dao实现类
        userService.setUserDao(new UserDaoOracle());
        userService.getUser();
    }
}

之前,程序是主动创建对象,控制权在程序员手上
使用set注入后,程序不在具有主动性,而是变成了被动的接收对象

3.IOC本质

- IOC: ( Inversion of Control )控制反转
IOC就是控制反转,通俗的说就是我们不用自己创建实例对象,这些都交给Spring的bean工厂帮我们创建管理。这也是Spring的核心思想,通过面向接口编程的方式来是实现对业务组件的动态依赖。这就意味着IOC是Spring针对解决程序耦合而存在的。在实际应用中,Spring通过配置文件(xml或者properties)指定需要实例化的java类(类名的完整字符串),包括这些java类的一组初始化值,通过加载读取配置文件,用Spring提供的方法(getBean())就可以获取到我们想要的根据指定配置进行初始化的实例对象,其实现方式是依赖注入(DI)

  • AOP就是将程序功能中的频繁出现或者与主业务逻辑代码相关度不高的代码抽离出来,通过切面编程的方式在想要调用的时候引入调用的思想。而这种思想并不是只限于Spring和java,AOP(面向切面)和OOP(面向对象)一样都是一种编程思想,这种思想的实现机制在Spring中便是应用了java的动态代理和java的反射。在实际编程中,我们通常会遇到一些交叉业务逻辑(比如:日志,事务,安全等等),这是我们就可以封装一个封面,然后注入到目标对象(具体的业务逻辑)中去。ps:很多方法都会抛出异常信息,这是我们就可以写一个拦截器,在这个类中实现记录错误日志的功能,再在Spring的xml配置文件中配置一个对这些要记录日志的方法的AOP拦截器,在这个方法执行后调用这个拦截器来记录日志。这样就不用每次抛出异常都要手动的去单独处理记录,提高了程序的内聚性。这种在调用某个方法之前/后想要自动执行一系列自定义操作的就是AOP思想。

4.HelloSpring

模块:spring_02_hello

  • 用xml的方式创建对象
    创建一个hello类
public class Hello {
    private String str;

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

    public String getStr() {
        return str;
    }
	//set方法不能少,spring通过set方法进行赋值
    public void setStr(String str) {
        this.str = str;
    }
}

在resources下创建一个xml文件(beans.xml)


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

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

beans>

测试

import com.it.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author shkstart
 * @create 2020-04-14 11:21
 */
public class MyTest {
    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean(); 获取对象 参数为 xml配置文件中 id的值
        Hello hello = (Hello) context.getBean("hello");
        //调用hello中的方法
        System.out.println(hello.getStr());
    }
}

顺势修改模块:spring_01_ioc01中代码
在resources下创建beans.xml配置文件


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
  
    <bean id="userDaoMysql" class="com.it.dao.UserDaoMysql"/>
    <bean id="userDaoOracle" class="com.it.dao.UserDaoOracle"/>


    <bean id="userServiceImpl" class="com.it.service.UserServiceImpl">
        
        <property name="userDao" ref="userDaoOracle"/>
    bean>

beans>

测试

public class MyTest {
    public static void main(String[] args) {

        //获取ApplicationContext对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //获得容器,需要哪个对象就get哪个
        UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("userServiceImpl");
        //调用方法
        userServiceImpl.getUser();
    }
}
如果想实现不同操作,去xml中修改配置文件
<property name="userDao" ref="userDaoOracle"/>

到现在我们再也不用去程序中修改代码了,要实现不同的操作,只需要在XML配置文件中进行修改,所谓IOC就一句话:对象由Spring来创建,管理,装配

5. IOC创建对象的方式

模块 spring_03_ioc02

  • 默认使用无参构造方法创建对象
    
   <bean id="user" class="com.it.pojo.User">
       
   bean>
  • 如需使用有参构造方法创建对象
    • 1.有参构造方法参数下标
        
     <bean id="user" class="com.it.pojo.User">
         <constructor-arg index="0" value="卡莎-index"/>
     bean>
    
  • 2.有参构造方法参数类型(不建议使用)
    
 <bean id="user" class="com.it.pojo.User">
     <constructor-arg type="java.lang.String" value="卡莎—type"/>
 bean>

- 3.有参构造方法参数名

    
 <bean id="user" class="com.it.pojo.User">
     <constructor-arg name="name" value="卡莎-name"/>
 bean>

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

6.Spring配置

  • 1.alias
    
   <alias name="user" alias="u"/>
  • 2,bean

   
   <bean id="user" class="com.it.pojo.User" name="u1 u2,u3;u4">

   bean>

- 3.import
一般来说一个项目会有很多配置文件 import会将多个配置文件 导入合并为一个总的配置文件使用的时候直接使用总的配置文件即可

    <import resource="beans.xml"/>
    <import resource="beans2.xml"/>
    <import resource="beans3.xml"/>

Spring5学习笔记_第3张图片

7.依赖注入(DI)

模块: spring_04_di
依赖:bean对象的创建依赖于容器
注入:bean对象的所有属性,由容器来注入

  • 1.构造器方式注入
    参考前面5

  • 2.set方式注入(重点)

环境搭建
Spring5学习笔记_第4张图片
com.it.pojo.Student代码

package com.it.pojo;

import java.util.*;

/**
 * @author shkstart
 * @create 2020-04-15 9:32
 */
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 String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWife() {
        return wife;
    }

    public void setWife(String wife) {
        this.wife = wife;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wife='" + wife + '\'' +
                ", info=" + info +
                '}';
    }
}

com.it,pojo.Address代码

package com.it.pojo;

/**
 * @author shkstart
 * @create 2020-04-15 9:32
 */
public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

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

resources.applicationContext.xml代码


<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.it.pojo.Address">
        <property name="address" value="雄安新区"/>
    bean>
    
    <bean id="student" class="com.it.pojo.Student">

        
        <property name="name" value="卡莎"/>

        
        <property name="address" ref="address"/>

        
        <property name="books">
            <array>
                <value>红楼梦value>
                <value>水浒传value>
                <value>三国演义value>
                <value>西游记value>
            array>
        property>

        
        <property name="hobbys">
            <list>
                <value>唱、跳、rapvalue>
                <value>篮球value>
            list>
        property>

        
        <property name="card">
            <map>
                <entry key="身份证" value="111111111122222222"/>
                <entry key="银行卡" value="444444444444444444"/>
            map>
        property>

        
        <property name="games">
            <set>
                <value>LOLvalue>
                <value>CFvalue>
            set>
        property>

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

        
        <property name="info">
            <props>
                <prop key="driver">com.mysql.jdbc.Driverprop>
                <prop key="url">jdbc:msql:localhost:3306/testprop>
                <prop key="username">rootprop>
                <prop key="password">xxxxxxprop>
            props>
        property>
    bean>
beans>

测试代码

public class MyTest {
    public static void main(String[] args) {
        //获取spring配置文件上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //利用context.getBean 获取bean
        Student student = (Student)context.getBean("student");
        //调用bean方法
        System.out.println(student);

        /*
        * 输出结果
        * Student{name='卡莎',
        * address=Address{address='雄安新区'},
        * books=[红楼梦, 水浒传, 三国演义, 西游记],
        * hobbys=[唱、跳、rap, 篮球],
        * card={身份证=111111111122222222, 银行卡=444444444444444444},
        * games=[LOL, CF],
        * wife='null',
        * info={password=xxxxxx, url=jdbc:msql:localhost:3306/test, driver=com.mysql.jdbc.Driver, username=root}}

         * */
    }
}

3.扩展注入
新建一个User类

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

    //有参构造必须有,因为要使用c标签注入
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

新建一个userBeans.xml配置文件


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

    
    <bean id="user" class="com.it.pojo.User" p:name="卡莎" p:age="20"/>

    
    <bean id="user2" class="com.it.pojo.User" c:age="30" c:name="小明"/>
    
   
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="user" class="com.it.pojo.User">
        
        <property name="name" value="${username}"/>
beans>

测试

    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userBeans.xml");
        User user = context.getBean("user", User.class);
        User user2 = context.getBean("user2",User.class);

        System.out.println(user);
        System.out.println(user2);
    }
}

注意:如果要使用 p标签注入 \ c标签注入\context标签注入 我们需要导入xml约束

       xmlns:p="http://www.springframework.org/schema/p"
       http://www.springframework.org/schema/p
        https://www.springframework.org/schema/p/spring-p.xsd

       xmlns:c="http://www.springframework.org/schema/c"
       http://www.springframework.org/schema/c
        https://www.springframework.org/schema/c/spring-c.xsd


       xmlns:context="http://www.springframework.org/schema/context"
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd

Spring5学习笔记_第5张图片

8.Bean作用域

Spring5学习笔记_第6张图片

  • 单例模式
  • Spring默认机制 在这里插入图片描述

    <bean id="user2" class="com.it.pojo.User" c:age="30" c:name="小明" scope="singleton"/>
  • 原型模式
  • 每次从容器中get 就会new一个新对象

在这里插入图片描述

    
    <bean id="user2" class="com.it.pojo.User" c:age="30" c:name="小明" scope="prototype"/>

9.Bean的自动装配

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

在Spring中有三种装配方式

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

环境搭建
Spring5学习笔记_第7张图片
com.it.pojo.People代码

package com.it.pojo;

/**
* @author shkstart
* @create 2020-04-15 14:10
*/
public class People {
   private String name;
   private Cat cat;
   private Dog dog;

   public String getName() {
       return name;
   }

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

   public Cat getCat() {
       return cat;
   }

   public void setCat(Cat cat) {
       this.cat = cat;
   }

   public Dog getDog() {
       return dog;
   }

   public void setDog(Dog dog) {
       this.dog = dog;
   }

   @Override
   public String toString() {
       return "People{" +
               "name='" + name + '\'' +
               ", cat=" + cat +
               ", dog=" + dog +
               '}';
   }
}

com.it.pojo.Cat代码

package com.it.pojo;

/**
 * @author shkstart
 * @create 2020-04-15 14:08
 */
public class Cat {
    public void speak(){
        System.out.println("The Cat is miao~ miao~ miao~");
    }
}

com.it.pojo.Dog代码

package com.it.pojo;

/**
 * @author shkstart
 * @create 2020-04-15 14:09
 */
public class Dog {
    public void speak(){
        System.out.println("The Dog is wang~ wang~ wang~");
    }
}

applicationContext.xml配置文件

    <bean id="cat" class="com.it.pojo.Cat"/>
    <bean id="dog" class="com.it.pojo.Dog"/>
	正常装配
    <bean id="people" class="com.it.pojo.People">
        <property name="name" value="人类"/>
       <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    bean><bean id="people" class="com.it.pojo.People" 
    p:name="人类" p:cat-ref="cat" p:dog-ref="dog"/>
  • byName 自动装配

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

    <bean id="cat" class="com.it.pojo.Cat"/>
    <bean id="dog" class="com.it.pojo.Dog"/>
    
    <bean id="people" class="com.it.pojo.People" autowire="byName">
        <property name="name" value="人类"/>
    bean>


beans>
  • byType 自动装配

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

    <bean id="cat" class="com.it.pojo.Cat"/>
    <bean id="dog" class="com.it.pojo.Dog"/>
    
    <bean id="people" class="com.it.pojo.People" autowire="byType">
        <property name="name" value="人类"/>
    bean>
beans>

总结:
- byName 的时候,需要保证所有bean的id值唯一,并且这个bean需要和自动注入属性的set方法值一致
- byType 的时候,需要保证所有的bean的class值唯一,并且这个bean需要和自动注入set方法类型一样

使用注解实现自动装配

使用注解实现自动装配需要
导入xml约束
添加 注解支持 context 标签


<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.it.pojo.Cat"/>
    <bean id="dog" class="com.it.pojo.Dog"/>
    <bean id="people" class="com.it.pojo.People"/>
beans>    

Spring5学习笔记_第8张图片
@Autowired
给people属性或set方法添加注解@Autowired

 package com.it.pojo;

import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author shkstart
 * @create 2020-04-15 14:10
 */
public class People {
    private String name;
    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;

    public String getName() {
        return name;
    }

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

    public Cat getCat() {
        return cat;
    }

//    @Autowired  autowired也可以在set方法中使用 也可以在属性中使用 可以省略set方法
    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

//    @Autowired    autowired也可以在set方法中使用 也可以在属性中使用 可以省略set方法
    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                ", cat=" + cat +
                ", dog=" + dog +
                '}';
    }
}

@Nullable 和 @Autowired(required = false)的使用

 //@Autowired(required = false)  表示该属性可以为null
    @Autowired(required = false)
    
//Nullable 表是该参数可以为null
    public People(@Nullable Cat cat ){
        this.cat = cat;
    }

Autowired 和 Qualifier(value = " xxx") 的组合使用
如果spring容器中存在多个cat bean 但还想要注解自动装配 我们就需要利用Qualifier(value=“xxx”) 来指定一个bean
Spring5学习笔记_第9张图片

	 //required = false  表示该属性可以为null
    @Autowired(required = false)
    //指定装配的bean为ioc容器中bean id 为 cat11 的bean对象
    @Qualifier(value="cat11")
    private Cat cat;

@Resource的使用 @Resource(name=“xxx”)

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

总结:@Resource 和 @Autowired 的区别
- 都是用来总动装配的,都可以放在属性字段上
- @Autowired 是通过byType方式实现的
- @Resource 默认通过byName实现,如果找不到名字,则通过byType

10.使用注解开发

模块:spring_06_annotation

使用注解开发需要确保maven项目下有org.springframework:spring-aop:5.2.4.RELEASE这个包在这里插入图片描述
然后就是导入context约束 和 注解支持


<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:component-scan base-package="com.it"/>

    
    <context:annotation-config/>
beans>
  • 属性的注入
// @Component 等价于 
@Component
public class User {
    //@Value  等价于 
   @Value("卡莎")
    public String name;

  • 衍生的注解
    Spring5学习笔记_第10张图片

  • 自动装配注解
    上方 9

  • 作用域注解

// @Component 等价于 
@Component
@Scope("singleton") // 标注为单例模式,原型模式 @Scope("prototype")
public class User {
  • 基本的书写格式
@Component //等价于 
@Scope("singleton") // 标注为单例模式,原型模式 @Scope("prototype")
public class User {
   @Value("卡莎")//属性赋值 等价于 
    public String name;
    @Autowired //自动装配
    public Other other;

11.使用Java方式配置Spring

模块:spring_07_appconfig

不需要配置文件,完全用java代码加注解完成spring配置
Spring5学习笔记_第11张图片
创建一个配置类 com.it.config.MyConfig

package com.it.config;

import com.it.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @author shkstart
 * @create 2020-04-16 9:24
 */
@Configuration//这个也会被Spring容器托管,注册到容器中,
                //因为它本身就是一个@component
                // @Configuration 表示这是一个配置类
                //相当于我们之前的applicationContext.xml
@ComponentScan("com.it") //扫描包下的类 该类下的注解可以使用
@Import(MyConfig2.class) //合并其他配置文件
public class MyConfig {

    @Bean //@Bean 相当于之前applicationContext.xml中的bean标签
          // 方法名 相当于 bean标签的id值
          // 返回值类型相当于 bean标签的class
    public User getUser(){
        return new User(); //返回值就是注入bean中的对象
    }
}

User.java代码

package com.it.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author shkstart
 * @create 2020-04-16 9:23
 */
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    @Value("卡莎")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
我们在编写一个配置类
@Configuration  //代表这是一个配置类
public class MyConfig2 {
}

在之前的配置类中我们来选择导入这个配置类
@Configuration
@Import(MyConfig2.class)  //导入合并其他配置类,类似于配置文件中的 import 标签
public class MyConfig {}

测试

import com.it.config.MyConfig;
import com.it.pojo.Password;
import com.it.pojo.User;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author shkstart
 * @create 2020-04-16 9:31
 */
public class MyTest {
    public static void main(String[] args) {
        //获取注解信息上下文对象  参数为配置类
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        //getBean 参数为  @bean注解下的方法名,返回值类型是@bean注解下方法的返回值类型
        User user = (User) context.getBean("getUser");
     //   Password password = context.getBean("getPassword",Password.class);
        System.out.println(user.getName());
  //      System.out.println(password.getPassword());

    }
}

12.静态代理模式

模块:spring_08_proxy
角色分析

  • 抽象角色:一般会用接口或抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,并顺带附属一些操作
  • 客户:访问代理对象的人
    Spring5学习笔记_第12张图片
  • 抽象角色
package com.it.demo01;

/**
 * @author shkstart
 * @create 2020-04-16 16:12
 */
//租房
public interface Rent {
    void rent();
}
  • 真实角色
package com.it.demo01;
/**
 * @author shkstart
 * @create 2020-04-16 16:11
 */
//房东
public class Host implements Rent{
	//房东只出租房子
    public void rent(){
        System.out.println("房东出租房子");
    }
}
  • 代理角色
package com.it.demo01;

/**
 * @author shkstart
 * @create 2020-04-16 16:12
 */
//代理  (中介)
public class Proxy implements Rent{
	
	//组合 获取房东对象
    private Host host;

    public Proxy() {
    }

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

    public void rent(){
        showHose();
        host.rent();
        heTong();
    }

    public void showHose(){
        System.out.println("代理带顾客看房子");
    }
    public void heTong(){
        System.out.println("代理带顾客签合同");
    }

}

  • 客户 (访问代理)
package com.it.demo01;
/**
 * @author shkstart
 * @create 2020-04-16 16:11
 */
//顾客
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

代理模式的好处:
- 可以使真实角色的操作更加纯粹,不去关注一些公共业务
- 公共业务交给代理,实现业务分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理,代码量翻倍

加深理解
demo02包下

13.动态代理

动态代理的角色和静态代理角色一样
动态代理的代理类是自动生成

  • 基于接口----- JDK动态代理

  • 清楚Proxy 类 和 InvocationHandler接口
    - InvocationHandler是由代理实例的调用处理程序实现的接口
    - Proxy提供了创建动态代理类和实例的静态方法

demo03

Spring5学习笔记_第13张图片
UserService接口 (抽象角色)

package com.it.demo03;

/**
 * @author shkstart
 * @create 2020-04-16 16:38
 */
//抽象角色
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

UserServiceImpl (真实角色)

package com.it.demo03;

/**
 * @author shkstart
 * @create 2020-04-16 16:39
 */
//真实角色
public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("添加了一个用户");
    }

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

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

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

ProxyInvocationHandler 动态代理类

package com.it.demo03;

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

/**
 * @author shkstart
 * @create 2020-04-16 17:27
 */
//用这个类自动生成代理类 需要实现InvocationHandler接口
public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;
    //set方法
    public void setTarget(Object target){
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy(){
        //类Proxy下的newProxyInstance方法
        //参数loader -  类加载器来定义代理类
        //参数interfaces - 代理类实现的接口列表
        //参数h - 调度方法调用的调用处理函数
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);
    }

    //处理代理实例并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //添加日志功能
        log(method.getName());
        Object result = method.invoke(target,args);
        return result;
    }

    //添加一个功能 日志功能
    public void log(String msg){
        System.out.println("执行了" + msg + "方法");
    }
}

Client(客户)

package com.it.demo03;

/**
 * @author shkstart
 * @create 2020-04-16 17:37
 */
public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色 不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //设置需要代理的对象
        pih.setTarget(userService);
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();

        proxy.add();
    }
}

动态代理好处
他具有静态代理的好处

  • 一个动态代理代理的是一个接口,一般就是对应一类业务
  • 一个动态代理可以代理多个类,只要实现了同一个接口即可

14.Spring实现AOP

模块: spring_09_aop

使用AOP织入,需要导入依赖


<dependency>
    <groupId>org.aspectjgroupId>
    <artifactId>aspectjweaverartifactId>
    <version>1.9.5version>
dependency>

Spring5学习笔记_第14张图片

方式一:使用spring的API接口【Spring API 接口实现】
Spring5学习笔记_第15张图片
afterLog.java代码

package com.it.log;

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

/**
 * @author shkstart
 * @create 2020-04-17 17:06
 */
//实现 AfterReturningAdvice
public class AfterLog implements AfterReturningAdvice {
    //afterReturning方法 意味着 UserServiceImpl方法执行完执行

    //参数:
    //returnValue : 返回值类型
    //method : 要执行目标对象方法
    //args : 参数值
    //target : 目标对象
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了" + method.getName() + "方法,返回了"+returnValue);
    }
}

beforeLog.java代码

package com.it.log;

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

/**
 * @author shkstart
 * @create 2020-04-17 17:00
 */
//实现 MethodBeforeAdvice
public class BeforeLog implements MethodBeforeAdvice {
    //before方法 意味在UserServiceImpl(真实角色)下方法执行之前执行

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

接口UserService

package com.it.service;

/**
 * @author shkstart
 * @create 2020-04-17 16:59
 */
//抽象角色
public interface UserService {
    void add();
    void delete();
    void update();
    void select();
}

接口实现类UserServiceImpl

package com.it.service;

/**
 * @author shkstart
 * @create 2020-04-17 16:59
 */
//真实角色
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("查询了一个用户");
    }
}

applicationContext.xml配置文件


<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.it.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.it.log.AfterLog"/>
    <bean id="beforeLog" class="com.it.log.BeforeLog"/>

    
    
    <aop:config>
        
        <aop:pointcut id="pointcut" expression="execution(* com.it.service.UserServiceImpl.*(..) )"/>

        
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    aop:config>

beans>

测试

import com.it.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author shkstart
 * @create 2020-04-17 17:29
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口 而不是实现类
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

方式二:自定义类 不实现接口(切面)【切面自定义】
新建一个diy包
DiyPointCut.java

package com.it.diy;

/**
 * @author shkstart
 * @create 2020-04-17 18:21
 */
public class DiyPointCut {

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

applicationContext.xml


<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.it.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.it.log.AfterLog"/>
    <bean id="beforeLog" class="com.it.log.BeforeLog"/>

    
    
    <bean id="diy" class="com.it.diy.DiyPointCut"/>
    
    <aop:config>
        
        <aop:aspect ref="diy">
            
            <aop:pointcut id="pointcut" expression="execution(* com.it.service.UserServiceImpl.*(..))"/>
            
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:before method="before" pointcut-ref="pointcut"/>
        aop:aspect>
    aop:config>
    beans>

方式三:使用注解实现AOP
创建一个类 AnnotationPointCut
在这里插入图片描述
AnnotationPointCut代码

package com.it.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * @author shkstart
 * @create 2020-04-18 9:08
 */
@Aspect    //使用注解标记这是一个切面
public class AnnotationPointCut {

    //execution 切入点,将方法切入到那个类的哪个方法中
    @Before("execution(* com.it.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("方法执行前------");
    }

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

    @Around("execution(* com.it.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("环绕增强执行前");
        pj.proceed();
        System.out.println("环绕增强执行后");
    }
}

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.it.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.it.log.AfterLog"/>
    <bean id="beforeLog" class="com.it.log.BeforeLog"/>


    
    
    <bean id="annotationPointCut" class="com.it.diy.AnnotationPointCut"/>
    
    <aop:aspectj-autoproxy/>
beans>

测试

import com.it.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author shkstart
 * @create 2020-04-17 17:29
 */
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口 而不是实现类
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

自我总结:我认为的AOP就是在一个已经封装好的类中,再加入一些功能型方法,在不改变源代码、不破坏原来代码结构的前题下,我们需要一个切面和切入点将要增加的代码横向插入到原来的类中

15.Spring整合Mybatis

模块:spring_10_mybatis
mybatis-spring文档:http://mybatis.org/spring/zh/sqlsession.html
导入依赖包


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring_studyartifactId>
        <groupId>org.examplegroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>spring_10_mybatisartifactId>
    <dependencies>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>

        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.2version>
        dependency>

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.6version>
        dependency>

        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-webmvcartifactId>
            <version>5.2.4.RELEASEversion>
        dependency>

        
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-jdbcartifactId>
            <version>5.2.4.RELEASEversion>
        dependency>

        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.5version>
        dependency>

        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatis-springartifactId>
            <version>2.0.4version>
        dependency>

    dependencies>
    
    <build>
        <resources>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>
project>

结构

Spring5学习笔记_第16张图片
编写mybatis模板,参考mybatis学习笔记
https://blog.csdn.net/weixin_44900198/article/details/105385963

创建spring-dao.xml配置文件


<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.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="001129"/>
    bean>

    
    <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:com/it/dao/*.xml"/>
    bean>

    
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
    bean>

beans>

mybatis-config.xml配置文件



    
            

<configuration>
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    settings>
    <typeAliases>
        <package name="com.it.pojo"/>
    typeAliases>

configuration>

applicationContext.xml配置文件


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

    
    
    <import resource="spring-dao.xml"/>

    
    <bean id="userServiceImpl" class="com.it.dao.UserMapperImpl">
        <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
    bean>
beans>

com.it.pojo.User.java

package com.it.pojo;

/**
 * @author shkstart
 * @create 2020-04-18 10:03
 */
public class User {
    private int id;
    private String name;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

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

com.it.dao.UserMapper接口

package com.it.dao;

import com.it.pojo.User;

import java.util.List;

/**
 * @author shkstart
 * @create 2020-04-18 10:05
 */
public interface UserMapper {
    List<User> selectUser();
}

com.it.dao.userMapper.xml 接口实现配置文件



<mapper namespace="com.it.dao.UserMapper">
    <select id="selectUser" resultType="user">
        select * from user ;
    select>

mapper>

com.it.dao.userMapperImpl实现类


import java.util.List;

/**
 * @author shkstart
 * @create 2020-04-18 10:54
 */
//创建实现类
public class UserMapperImpl implements UserMapper {
    
    //获取SqlSessionTemplate 就相当于SqlSession都是增删改查操作
    private SqlSessionTemplate sqlSessionTemplate;

    //set注入方法
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate){
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    public List<User> selectUser() {
        //通过SqlSessionTemplate.getMapper 方法获取UserMapper
        UserMapper userMapper = sqlSessionTemplate.getMapper(UserMapper.class);
        //执行selectUser方法
        return userMapper.selectUser();
    }
}

测试

import com.it.dao.UserMapper;
import com.it.dao.UserMapperImpl;
import com.it.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author shkstart
 * @create 2020-04-18 10:08
 */
public class MyTest {
    @Test
    public void selectUser() throws IOException {
/*        String resources = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resources);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
        List list = usermapper.selectUser();
        for (User user : list) {
            System.out.println(user);
        }*/

        //上面利用mybatis的繁琐操作可以省略了
        
        //获取Spring配置文件上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过getBean 创建并获取对象
        UserMapperImpl userServiceImpl = context.getBean("userServiceImpl", UserMapperImpl.class);
        //掉用对象的方法 
        List<User> list = userServiceImpl.selectUser();
        for (User user : list) {
            System.out.println(user);
        }
    }
}

总结方式一:整合Mybatis Spring
基本步骤
- 创建操作数据库的配置文件 也就是替换mybatis-config.xml 里内容的配置文件
- 在此配置文件中配置 数据源DataSource 和 SqlSessionFactory 和 SqlSessionTemplate
- 编写一个Mapper实现类 操作方法在此类中
- 将此类注册到spring
- 测试

16.声明式事务

spring-dao.xml


    
        
    

    
    
    
        
        
        
            
            
            
            
            
            
        
    
    
    
    
    
        
        
        
        
    

你可能感兴趣的:(Spring)