Spring_day01

第一章、Spring框架的介绍

1. 自定义Bean工厂解耦

  知识补充:

    JDK的类:

      java.util.ResourceBundle:专门用来读取bean.properties

      方法:

        (1) ResourceBundle类静态方法 getBundle(配置文件名)返回本类对象

        (2) ResourceBundle对象的方法getString(配置文件的键)返回值

  方法测试demo

public static void main(String[] args) {
        //读取bean.properties
        //JDK的类,java.util.ResourceBundle 专门对付bean.properties
        //ResourceBundle类静态方法 getBundle(配置文件名)返回本类对象

        ResourceBundle bundle = ResourceBundle.getBundle("bean");
        //bundle对象的方法getString(配置文件的键)返回值
        String userService = bundle.getString("UserService");
        System.out.println("userService = " + userService);
    }

 

(1)dao层

public interface UserDao {
}
public class UserDaoImpl implements UserDao {
}

(2)service层

public interface UserService {
}
public class UserServiceImpl implements UserService { }

(3)bean工厂类

/*
    BeanFactory:读取配置文件,创建对象
* */
public class BeanFactory implements Serializable {

    /*
        定义静态方法,传递接口类型,传递接口的class对象
        返回个接口的实现类对象

        Class<T> clazz 传递接口的Class对象,泛型T就是接口类型
    * */
    public static <T> T getInstance(Class<T> clazz){
        T obj = null;
        try {
            ResourceBundle bundle = ResourceBundle.getBundle("bean");
            //传递键获取值,一个类的全路径名
            //Class类的方法,getSimpleName,获取class对象的类的简称
            String string = bundle.getString(clazz.getSimpleName());
            //反射创建对象
            Class cla = Class.forName(string);
            obj = (T)cla.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }
}

(4)bean.properties文件

UserService=com.atguigu.service.impl.UserServiceImpl
UserDao=com.atguigu.dao.impl.UserDaoImpl

(5)测试类

public class MainTest {
    @Test
    public void testMyIOC() {
        //调用BeanFactory的静态方法getInstance(接口名) 返回实现类对象
        UserService userService = BeanFactory.getInstance(UserService.class);
        System.out.println("userService = " + userService);

        UserDao instance = BeanFactory.getInstance(UserDao.class);
        System.out.println("instance = " + instance);
    }
}

第二章、SpringIOC

1. IOC容器的概念和作用

  (1)概念:inverse of control (反转控制/控制反转),我们之前在一个java类中通过new的方式去引入外部资源(其他类等),这叫正向;现在Spring框架帮我们去new,你什么时候需要你去问Spring框架要,这就是反转(创建对象权利的一个反转)

  (2)作用:IOC解决程序耦合问题

2. IOC容器的使用

  (1)导入Spring框架依赖的jar包

     <!--
            添加spring框架的jar
            context:上下文,框架核心包
        -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

  (2)定义类

package com.atguigu.ioc;
/*
    HappyComponent 类的对象,放在Spring框架的IOC容器中存储
    IOC:控制反转()
* */
public class HappyComponent {public void doWork() {
        System.out.println("component do work ...");
    }
}

  (3)放进IOC容器中

  标签名字:<bean>

    属性: id :这个对象的唯一标识

          class:配置的类的全类名

       scope:对象的作用域,spring框架的对象容器中对象的作用域是两个单例模式(默认)和多例模式。                 

           scope="singleton" 单例模式的配置

           scope="prototype" 多例模式的配置

注意:

  • singleton:默认值,单例,项目全局内存中只有一个对象,一般在使用Spring的时候保持默认值即可

  • prototype:原型的意思,在这里是多例,每引用或者getBean一次,Spring框架就返回一个新的对象,比如SqlSession这个特殊的对象

 

    <!--
        配置HappyComponent类的对象,放在对象容器中
    -->
    <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent" scope="singleton"></bean>

  (4)通过IOC容器获取对象(不强转)

    @Test
    public void testSpringIOCNoCast(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //方式一:context对象的方法,获取容器中的对象:getBean(要获取的对象的类的class对象)
        HappyComponent happyComponent = context.getBean(HappyComponent.class);
        happyComponent.doWork();

        //方式二:getBean("配置文件中的id属性值",要获取的对象,类的class对象)
        //HappyComponent happyComponent1 = context.getBean("happyComponent", HappyComponent.class);
        //happyComponent1.doWork();
    }

  注意:SpringIOC对象容器的本质:Map集合ConcurrentHashMap

  (5)IOC容器中的生命周期

init-method="initMethod" destroy-method="destroyMethod"
  • init-method:对象初始化调用的方法
  • destroy-method:对象销毁之前调用的方法

     (5-1)HappyComponent类中添加两个方法initMethod()、destory()

public class HappyComponent {
    /*
        自己定义方法:声明周期的初始化方法
        initMethod() Spring框架创建对象,调用方法 initMethod
    * */
    public void initMethod(){
        System.out.println("对象初始化方法");
    }
    public void destory(){
        System.out.println("对象销毁的方法");
    }
    public void doWork() {
        System.out.println("component do work ...");
    }
}

    (5-2) ApplicationContext.xml文件中添加调用初始化、销毁方法的属性

<!--
    配置对象的生命周期:
        属性:init-method,配置方法名即可
        属性:destory-method,配置方法名即可
 -->
    <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent" scope="singleton" init-method="initMethod" destroy-method="destory"></bean>

    (5-2)测试方法

    销毁方法,只有销毁ApplicationContext对象才会销毁

@Test
    public void testSpringIOCLife(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        HappyComponent happyComponent = context.getBean(HappyComponent.class);
        happyComponent.doWork();

        //销毁容器中的对象,关闭容器
        ClassPathXmlApplicationContext context1 =(ClassPathXmlApplicationContext) context;
        context1.close();
    }

 

第三章、依赖注入(DI)

  • dependency Inject(依赖注入的意思)
  • IOC和DI的区别

    (1) IOC和DI是一个事情,只是描述的角度不同

    (2) DI 是 IOC 的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。

  • 结论是:IOC 就是一种反转控制的思想, 而 DI 是对 IOC 的一种具体实现。

 1. set方法注入

  (1)创建对象(get和set方法用lombok插件代替)

@Data
public class HappyComponent {
    private String componentName;
}

  (2)将对象注入spring中

<!--
        配置对象,放在spring框架IOC容器中
        利用set方法,为componentName字段赋值
            bean标签的子标签:property 为字段赋值
                property标签的属性:name set方法名,去掉set字母,字母小写
                property标签的属性:value 字段值
    -->
    <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent">
        <property name="componentName" value="张三"/>
    </bean>

  (3)测试依赖注入,set方法注入

    @Test
    public void testDiSet(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        HappyComponent happyComponent = context.getBean(HappyComponent.class);
        System.out.println("componentName = " + happyComponent.getComponentName());
    }

2. set方法注入——讲一个对象作为另一个对象的一个字段注入

  (1)创建对象

@Data
public class HappyMachine {
    private String machineName;
    //将HappyComponent对象作为该对象的一个属性
    private HappyComponent happyComponent;
}

  (2)讲对象注入spring中

  <!--
        为一个类的字段,注入另一个类的对象的时候,property标签不能使用value属性
        使用另个一个属性 ref = '另一个对象的id值'
    -->
    <bean id="machine" class="com.atguigu.ioc.HappyMachine">
        <property name="machineName" value="Java虚拟机"/>
        <property name="happyComponent" ref="happyComponent"/>
    </bean>
  
    <bean id="happyComponent" class="com.atguigu.ioc.HappyComponent">
        <property name="componentName" value="张三"/>
    </bean>

  (3)测试

    /*
        测试一个类型,作为另一个类型的字段出现
        set方法注入
    * */
    @Test
    public void testDiSet2(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        HappyMachine happyMachine = context.getBean(HappyMachine.class);
        System.out.println("happyMachine = " + happyMachine);
    }

3. 构造方法注入

  (1)创建类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private Double money;
    private String name;
}

  (2)将Person对象注入Spring配置文件中

  <!--
        配置Person对象
        构造方法:将数据,注入到类的字段中
        标签:constructor-arg
            name属性:表示构造方法的参数名
    -->
    <bean class="com.atguigu.ioc.Person" id="person">
        <constructor-arg name="id" value="1"/>
        <constructor-arg name="money" value="199.0"/>
        <constructor-arg name="name" value="王五"/>
    </bean>

  (3)测试

    /*
        测试依赖注入
        构造方法
    * */
    @Test
    public void DiConstructor(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        Person person = context.getBean(Person.class);
        System.out.println("person = " + person);
    }

4. 特殊值的注入处理

  null值

  (1)创建类

@Data
public class ValueClass {
    private String commonValue;
}

  (2)指定commonValue字段为控制

<bean class="com.atguigu.ioc.ValueClass" id="valueClass">
        <!--set方法注入数据,字段名commonValue 赋值特殊值,null 常量-->
        <property name="commonValue">
            <null/>
        </property>
</bean>

  (3)测试,结果报空指针异常

    @Test
    public void testDiValue(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        ValueClass valueClass = context.getBean(ValueClass.class);
        boolean b = valueClass.getCommonValue().equals("abc");
        System.out.println(b);//报空指针异常
    }

5. 复杂数据类型的注入(数组、List、Set、Map、Properties)

  (1)创建类

@Data
public class ComplexValue {
    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myPro;
}

  (2)讲对象注入Spring配置文件中

   <!--
        配置对象ComplexValue:对象中字段进行数据注入
        字段都是容器
    -->
    <bean class="com.atguigu.ioc.ComplexValue" id="complexValue">
        <!--set方法注入-->
        <property name="myStrs">
            <!--输入数组,property标签子标签 array 输入的数据是数组容器-->
            <array>
                <!--注入数组元素-->
                <value>java</value>
                <value>c++</value>
                <value>mysql</value>
                <value>Machine</value>
            </array>
        </property>
        <!--注入list集合-->
        <property name="myList">
            <list>
                <value>java - list</value>
                <value>C++ - list</value>
                <value>python - list</value>
                <value>c - list</value>
            </list>
        </property>
        <!--注入set集合,set集合是不重复元素-->
        <property name="mySet">
            <!--property的子标签 set-->
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
                <value>d</value>
            </set>
        </property>
        <!--注意Map集合-->
        <property name="myMap">
            <map>
                <!--
                    Map子标签 entry
                    entry标签的属性 key = Map的键
                    entry标签的属性 value = Map的值
                -->
                <entry key="Eden" value="伊甸园"/>
                <entry key="survivor0" value="幸存者0"/>
                <entry key="survivor1" value="幸存者1"/>
            </map>
        </property>
        <!--注入Properties集合,Map的实现类,键值对,无序的哈希表,线程安全-->
        <property name="myPro">
            <!--property子标签props-->
            <props>
                <!--
                    prop配置单个键值对
                -->
                <prop key="Eden">伊甸园</prop>
                <prop key="survivor0">幸存者0</prop>
                <prop key="survivor1">幸存者1</prop>
            </props>
        </property>
    </bean>

  (3)测试

  补充知识点:

    Properties类

      方法:Set<String> stringPropertyNames():返回此属性列表中的键集

          String getProperty(String key):根据键返回值

/*
        测试依赖注入,输入数组容器
    * */
    @Test
    public void testDiArray(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        ComplexValue complexValue = context.getBean(ComplexValue.class);
        //测试依赖注入,输入数组容器
        String[] myStrs = complexValue.getMyStrs();
        for (String s : myStrs) {
            System.out.println("s = " + s);
        }
        //测试依赖注入,注入List集合
        List<String> myList = complexValue.getMyList();
        System.out.println("myList = " + myList);
        //测试依赖注入,注入Set集合
        Set<String> mySet = complexValue.getMySet();
        System.out.println("mySet = " + mySet);
        //测试依赖注入,注入Map集合
        Map<String, String> myMap = complexValue.getMyMap();
        System.out.println("myMap = " + myMap);
        //测试依赖注入,注入Properties
        Properties myPro = complexValue.getMyPro();
        System.out.println("myPro = " + myPro);
        //myPro集合对象stringPropertyNames() 将集合的键,存储到Set集合 == Map的方法keySet()
        Set<String> set = myPro.stringPropertyNames();
        for (String s : set) {
            String property = myPro.getProperty(s);
            System.out.println(s+" = " + property);
        }
    }

  (4)运行结果

s = java
s = c++
s = mysql
s = Machine
myList = [java - list, C++ - list, python - list, c - list]
mySet = [a, b, c, d]
myMap = {Eden=伊甸园, survivor0=幸存者0, survivor1=幸存者1}
myPro = {survivor0=幸存者0, survivor1=幸存者1, Eden=伊甸园}
survivor0 = 幸存者0
survivor1 = 幸存者1
Eden = 伊甸园

 第四章、Schema约束

  对于xml的新型约束,控制xml该怎么写。常用的约束有DTD,和Schema,Schema逐步取代DTD

  官方约束:显示约束文档xsd怎么写,xsd限制我们自己定义的xml

  •  Schema约束支持命名空间namespace,就是java中的import导包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:a="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">
    <!--
        命名空间:xmlns = xml namespace 命名空间  http://www.springframework.org/schema/beans 命名空间的名字 具有全球唯一性
        Schema官方约束: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 :命名空间对应的约束文件地址 写的任何标签,都是来自于命名空间 http://www.springframework.org/schema/beans 对应的约束文件 spring-bean.xsd
--> </beans>