Spring对IOC的实现

控制反转IOC

+ 控制反转是一种思想 + 控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则 + 控制反转,反转是什么? - 将对象的创建权利交出去,交给第三方容器负责 - 将对象和对象之间关系的维护权交出去,交给第三方容器负责 + 控制反转这种思想如何实现: - DI(Dependency Injection):依赖注入

依赖注入DI

依赖注入 实现了控制反转的思想

Spring通过依赖注入的方式来完成Bean管理

Bean管理:Bean对象的创建,Bean对象中属性的赋值(Bean对象之间关系的维护)

依赖注入:

- 依赖指的是对象和对象之间的关联关系
- 注入指的是一种数据传递行为,通过注入行为来让对象和对象之间产生关系

依赖注入常见的实现方式:

✅第一种:set注入

set注入是居于set方法实现的,底层通过反射机制调用属性对象的set方法然后给属性赋值,让两个对象之间产生关系。这种方式要求属性必须对外提供set方法。

✅第一种:构造方法注入

核心原理:通过调用构造方法来给属性赋值

依赖注入代码实例

set注入
> 注意点: > > 1. 在bean标签中class对标的都是类,所以在MVC架构中填写实现类的实现接口是不可行的 > 2. property的name是set方法的XXX,比如示例中userDao对应的方法就是实现类中的setUserDao方法 > + 通过property标签获取到属性名:userDao > + 通过属性名推断出set方法名:setUserDao > + 通过反射机制调用setUserDao()方法给属性赋值 > - property标签的`** name**`是属性名。 > - property标签的`** ref**`是要注入的bean对象的id。(** 通过ref属性来完成bean的装配,这是bean最简单的一种装配方式**。装配指的是:** 创建系统组件之间关联的动作**) > + 由此可以推断出: > - setUsername() 演变为 username > - setPassword() 演变为 password > - setUserDao() 演变为 userDao > - setUserService() 演变为 userService >
<?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="userDaoBean" class="com.powernode.Dao.UserDaoImpl"/>

    <bean id="userServiceBean" class="com.powernode.Service.UserServiceImpl">
        <property name="userDao" ref="userDaoBean"/>
    </bean>
</beans>
package com.powernode.Dao;

/**
 * @Author: -
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public interface UserDao {
    void add();
    void update();
}

---------------------------------------------------------------------------------

package com.powernode.Dao;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public class UserDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("Mysql数据库正在新增用户....");
    }

    @Override
    public void update() {
        System.out.println("Mysql数据库正在修改用户....");
    }
}
package com.powernode.Service;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public interface UserService {
    void add();
    void update();
}

package com.powernode.Service;

import com.powernode.Dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

---------------------------------------------------------------------------------

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public class UserServiceImpl implements UserService{

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    public UserDao userDao;

    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void add() {
        logger.info("add():userDao:{}", userDao);
        userDao.add();
    }

    @Override
    public void update() {
        logger.info("update():userDao:{}", userDao);
        userDao.update();
    }
}

测试程序

package com.powernode.Test;

import com.powernode.Service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/23 16:29
 */
public class Test {

    private Logger logger = LoggerFactory.getLogger(Test.class);

    @org.junit.Test
    public void setTest(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beansSetDI.xml");

        UserService userServiceBean = (UserService) beans.getBean("userServiceBean");
        userServiceBean.add();
        /**
         * userDao:com.powernode.Dao.UserDaoImpl@6e4de19b
         * Mysql数据库正在新增用户....
         */
        userServiceBean.update();
        /**
         * userDao:com.powernode.Dao.UserDaoImpl@6e4de19b
         * Mysql数据库正在修改用户....
         */
    }
}

构造函数注入
> 构造函数的引用非简单类型和set一样,都是使用`** ref**`引用当前配置文件中已经定义的bean id > > 1. 构造函数的constructor-arg表示定义构造函数的参数,其中存在两种写法 > - index,index表示参数的个数,0表示第一个参数,以此类推 > - name标识参数名称,name所对应的并非参数类型,而是参数命名,比如参数为:"UserDao abcd",那么配置文件中应该这么写:name="abcd" >
<?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="userDaoBean" class="com.powernode.Dao.UserDaoImpl"/>

    <!--第一种写法,使用index标识参数-->
    <bean id="userServiceBean" class="com.powernode.Service.UserServiceImpl2">
        <constructor-arg index="0" ref="userDaoBean"/>
    </bean>

    <!--第二种写法,使用name标识参数,name所对应的并非参数类型,而是参数命名-->
    <bean id="userServiceBean2" class="com.powernode.Service.UserServiceImpl2">
        <constructor-arg name="userDao" ref="userDaoBean"/>
    </bean>
</beans>
package com.powernode.Dao;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public interface UserDao {
    void add();
    void update();
}

---------------------------------------------------------------------------------

package com.powernode.Dao;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public class UserDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("Mysql数据库正在新增用户....");
    }

    @Override
    public void update() {
        System.out.println("Mysql数据库正在修改用户....");
    }
}
package com.powernode.Service;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public interface UserService {
    void add();
    void update();
}

------------------------------------------------------------------------------------

package com.powernode.Service;

import com.powernode.Dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/19 15:19
 */
public class UserServiceImpl2 implements UserService{

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl2.class);

    public UserDao userDao;

    public UserServiceImpl2(UserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void add() {
        logger.info("add():userDao:{}", userDao);
        userDao.add();
    }

    @Override
    public void update() {
        logger.info("update():userDao:{}", userDao);
        userDao.update();
    }
}

测试程序

package com.powernode.Test;

import com.powernode.Service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/23 16:29
 */
public class Test {

    private Logger logger = LoggerFactory.getLogger(Test.class);
    
    @org.junit.Test
    public void constructorTest(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beansConstructor.xml");

        UserService userServiceBean = (UserService) beans.getBean("userServiceBean2");
        userServiceBean.add();
        /**
         2024-09-23 17:00:10 397 [main] INFO com.powernode.Service.UserServiceImpl2 - add():userDao:com.powernode.Dao.UserDaoImpl@7adf16aa
         Mysql数据库正在新增用户....
         */
        userServiceBean.update();
        /**
         2024-09-23 17:00:10 410 [main] INFO com.powernode.Service.UserServiceImpl2 - update():userDao:com.powernode.Dao.UserDaoImpl@7adf16aa
         Mysql数据库正在修改用户....
         */
    }
}

set注入专题

注入外部Bean
注入外部Bean的意思是在配置property标签时,采用ref的形式配置
<?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">

    <!-- set内外部注入bean  -->
    <bean id="userDaoBean" class="com.powernode.Dao.UserDaoImpl"/>

    <!--外部注入-->
    <bean id="userServiceBean" class="com.powernode.Service.UserServiceImpl">
        <property name="userDao" ref="userDaoBean"/>
    </bean>
</beans>
@org.junit.Test
public void shapeTest(){
    ApplicationContext beans = new ClassPathXmlApplicationContext("beansShape.xml");

    UserService userServiceBean = (UserService) beans.getBean("userServiceBean");
    UserDao userDaoBean = (UserDao) beans.getBean("userDaoBean");
    logger.info("userDaoBean:{}", userDaoBean);
    // userDaoBean:com.powernode.Dao.UserDaoImpl@18518ccf
    userServiceBean.add();
    /**
         add():userDao:com.powernode.Dao.UserDaoImpl@18518ccf
         Mysql数据库正在新增用户....
     */
    userServiceBean.update();
    /**
         update():userDao:com.powernode.Dao.UserDaoImpl@18518ccf
         Mysql数据库正在修改用户....
     */
}
注入内部Bean
注入外部Bean的意思是在配置property标签时,现阶段直接创建;

与外部注入Bean的区别:外部注入Bean中ref引用的和userService使用的对象是同一个对象;内部注入因为是新创建的,所以每一个创建出来的bean对象都不一样

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

  <!-- set内外部注入bean  -->
  <bean id="userDaoBean" class="com.powernode.Dao.UserDaoImpl"/>

  <!--内部注入-->
  <bean id="userServiceBean" class="com.powernode.Service.UserServiceImpl">
     <property name="userDao">
         <bean class="com.powernode.Dao.UserDaoImpl"/>
     </property>
  </bean>
</beans>
@org.junit.Test
public void shapeTest(){
    ApplicationContext beans = new ClassPathXmlApplicationContext("beansShape.xml");

    UserService userServiceBean = (UserService) beans.getBean("userServiceBean");
    UserDao userDaoBean = (UserDao) beans.getBean("userDaoBean");
    logger.info("userDaoBean:{}", userDaoBean);
    // userDaoBean:com.powernode.Dao.UserDaoImpl@4c6daf0
    userServiceBean.add();
    /**
         add():userDao:com.powernode.Dao.UserDaoImpl@6d0b5baf
         Mysql数据库正在新增用户....
     */
    userServiceBean.update();
    /**
         update():userDao:com.powernode.Dao.UserDaoImpl@6d0b5baf
         Mysql数据库正在修改用户....
     */
}
注入简单类型
进行注入的时候,对象的属性是另外一个对象的时候,我们使用`set`+ `ref`注入。如果注入的对象属性是基本数据类型,也是采用set注入的方式给该属性赋值。

注意点:

property标签的name属性为set方法去掉set后的首字母小写

<?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.powernode.entity.User">
        <property name="age" value="20"/>
    </bean>

    <!--完整写法-->
    <bean id="userBean" class="com.powernode.entity.User">
        <property name="age">
            <value>22</value>
        </property>
    </bean>
</beans>
    @org.junit.Test
    public void userTest(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("simpleType.xml");

        User user = (User) beans.getBean("user");
        User user2 = (User) beans.getBean("userBean");
        System.out.println(user.toString());
        //  User{age=20}

        System.out.println(user2);
    }
简单类型
简单类型包括哪些?
    public static boolean isSimpleValueType(Class<?> type) {
        return !isVoidType(type) && 
        (isPrimitiveOrWrapper(type) || 
         Enum.class.isAssignableFrom(type) || 
         CharSequence.class.isAssignableFrom(type) || 
         Number.class.isAssignableFrom(type) || 
         Date.class.isAssignableFrom(type) || 
         Temporal.class.isAssignableFrom(type) || 
         ZoneId.class.isAssignableFrom(type) || 
         TimeZone.class.isAssignableFrom(type) || 
         File.class.isAssignableFrom(type) || 
         Path.class.isAssignableFrom(type) || 
         Charset.class.isAssignableFrom(type) || 
         Currency.class.isAssignableFrom(type) || 
         InetAddress.class.isAssignableFrom(type) || 
         URI.class == type || 
         URL.class == type ||
         UUID.class == type || 
         Locale.class == type || 
         Pattern.class == type || 
         Class.class == type);
    }


// 分析 isPrimitiveOrWrapper
    public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
        Assert.notNull(clazz, "Class must not be null");
        return clazz.isPrimitive() || isPrimitiveWrapper(clazz);
    }

    /**
     * Determines if the specified {@code Class} object represents a
     * primitive type.
     *
     * <p> There are nine predefined {@code Class} objects to represent
     * the eight primitive types and void.  These are created by the Java
     * Virtual Machine, and have the same names as the primitive types that
     * they represent, namely {@code boolean}, {@code byte},
     * {@code char}, {@code short}, {@code int},
     * {@code long}, {@code float}, and {@code double}.
     *
     * <p> These objects may only be accessed via the following public static
     * final variables, and are the only {@code Class} objects for which
     * this method returns {@code true}.
     *
     * @return true if and only if this class represents a primitive type
     *
     * @see     java.lang.Boolean#TYPE
     * @see     java.lang.Character#TYPE
     * @see     java.lang.Byte#TYPE
     * @see     java.lang.Short#TYPE
     * @see     java.lang.Integer#TYPE
     * @see     java.lang.Long#TYPE
     * @see     java.lang.Float#TYPE
     * @see     java.lang.Double#TYPE
     * @see     java.lang.Void#TYPE
     * @since 1.1
     */
    @IntrinsicCandidate
    public native boolean isPrimitive();

由源码可知简单类型包括:

基本数据类型、基本类型对应的包装类、String或者其他的****CharSequence子类、Enum子类、Number子类、Date子类、URIURLTemporal子类LocalClass、ZoneId、TimeZone、File、Path、Charset、Currency、InetAddress、UUID、Pattern

简单类型代码示例
> 注意:这里只测常见的,** Currency、InetAddress等**工具类不做测试 >
<?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">

    <!--&lt;!&ndash;简化写法&ndash;&gt;-->
    <!--<bean id="user" class="com.powernode.entity.User">-->
    <!--    <property name="age" value="20"/>-->
    <!--</bean>-->
    
    <!--&lt;!&ndash;完整写法&ndash;&gt;-->
    <!--<bean id="userBean" class="com.powernode.entity.User">-->
    <!--    <property name="age">-->
    <!--        <value>22</value>-->
    <!--    </property>-->
    <!--</bean>-->
    
    
    <bean id="simpleTypeBean" class="com.powernode.entity.AllSimpleType">
        <!--基本数据类型-->
        <property name="b" value="2"/>
        <property name="s" value="3"/>
        <property name="i" value="30"/>
        <property name="l" value="20000000"/>
        <property name="f" value="20.1"/>
        <property name="d" value="20.222"/>
        <property name="flag" value="true"/>
        <property name="c" value="s"/>
        
        <!--基本数据类的包装类-->
        <property name="b1" value="3"/>
        <property name="s1" value="4"/>
        <property name="i1" value="40"/>
        <property name="l1" value="999999999999999"/>
        <property name="f1" value="21.1"/>
        <property name="d1" value="21.222"/>
        <property name="flag1" value="false"/>
        <property name="c1" value="b"/>

        <!--String-->
        <property name="str" value="mySimpleType"/>

        <!--注意:value后面的日期字符串格式必须是Date对象的toString()方法执行的结果-->
        <!--如果想使用其他格式的日期字符串,就需要进行特殊处理-->
        <property name="date" value="Fri Sep 30 15:26:38 CST 2022"/>

        <!--枚举 Enum-->
        <property name="season" value="WINTER"/>
        <!--uri-->
        <property name="uri" value="/save.do"/>
        <!--url  spring6之后,会自动检查url是否有效,如果无效会报错-->
        <property name="url" value="http://www.baidu.com"/>
        <!--localDate-->
        <property name="localDate" value="EPOCH"/>
        <!--local
            java.util.Locale 主要在软件的本地化时使用。它本身没有什么功能,
      			更多的是作为一个参数辅助其他方法完成输出的本地化。
      	-->
        <property name="locale" value="CHINESE"/>
        <!--class-->
        <property name="clazz" value="com.powernode.entity.AllSimpleType"/>
    </bean>
</beans>
    @org.junit.Test
    public void simpleType(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("simpleType.xml");

        AllSimpleType simpleTypeBean = (AllSimpleType) beans.getBean("simpleTypeBean");
        System.out.println(simpleTypeBean);
        /**
         AllSimpleType{b=2, s=3, i=30, l=20000000, f=20.1, d=20.222, flag=true, c=s, b1=3, s1=4, i1=40, l1=999999999999999, f1=21.1, d1=21.222, flag1=false, c1=b, str='mySimpleType', date=Sat Oct 01 05:26:38 CST 2022, season=WINTER, uri=/save.do, url=http://www.baidu.com, localDate=1970-01-01, locale=chinese, clazz=class com.powernode.entity.AllSimpleType}
         */
    }
  • 如果把Date当做简单类型的话,日期字符串格式不能随便写。格式必须符合Date的toString()方法格式。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给Date类型的属性的。
  • spring6之后,当注入的是URL,那么这个url字符串是会进行有效性检测的。如果是一个存在的url,那就没问题。如果不存在则报错。
级联属性赋值(了解)
```xml <?xml version="1.0" encoding="UTF-8"?>
<property name="name" value="张三"/>

<!--要点1:以下两行配置的顺序不能颠倒-->
<property name="clazz" ref="clazzBean"/>
<!--要点2:clazz属性必须有getter方法-->
<property name="clazz.name" value="高三一班"/>
```
package com.rui.spring6.beans;

public class Clazz {
    
    private String name;

    //无惨构造
    public Clazz() {
    }

    //有参构造
    public Clazz(String name) {
        this.name = name;
    }

    //setter and getter
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

使用级联属性赋值需要注意两点:

1、配置的顺序不能颠倒

2、clazz属性必须提供getter方法

注入数组
注入数组根据数组类型分为两种:简单类型、非简单类型
  • 如果数组中是简单类型,使用value标签
  • 如果数组中是非简单类型,使用ref标签
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <!--数组类型简单类型-->
    <bean id="personBean" class="com.powernode.entity.Person">
        <property name="favariteFoods">
            <array>
                <value>鸡排</value>
                <value>汉堡</value>
                <value>鹅肝</value>
            </array>
        </property>
    </bean>

    <!--数组类型非简单类型-->
    <bean id="orderBean" class="com.powernode.entity.Order">
        <property name="goods">
            <array>
                <!--使用ref标签定位 bean属性选择对象-->
                <ref bean="goods1"/>
                <ref bean="goods2"/>
            </array>
        </property>
    </bean>
</beans>
    @org.junit.Test
    public void simpleArrayType(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beans-array-type.xml");

        Person personBean = (Person) beans.getBean("personBean");
        System.out.println(personBean);
        //Person{favariteFoods=[鸡排, 汉堡, 鹅肝]}

        Order orderBean = (Order) beans.getBean("orderBean");
        System.out.println(orderBean);
        //Order{goods=[Goods{name='香蕉'}, Goods{name='苹果'}]}
    }
注入List集合
> List集合:有序可重复。 > > + 注入List集合的时候使用标签 > + List集合中是简单类型使用`value`标签,反之使用`ref`标签 >
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <bean id="dataStructureBean" class="com.powernode.entity.DataStructure">
        <!--list  使用list标签 无序列表-->
        <property name="list">
            <list>
                <value>listOne</value>
                <value>listTwo</value>
            </list>
        </property>
    </bean>
</beans>
注入Set集合
> + 使用标签。 > + set集合中元素是简单类型的使用`value`标签,反之使用`ref`标签 >
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <bean id="dataStructureBean" class="com.powernode.entity.DataStructure">
        <!--set 使用set 有序列表-->
        <property name="set">
            <set>
                <value>setOne</value>
                <value>setThree</value>
                <value>setOneW</value>
            </set>
        </property>
    </bean>
</beans>
注入Map集合
> + 使用 标签。 > + 如果key是简单类型,使用key属性,反之使用`key-ref`属性 > + 如果value是简单类型,使用value属性,反之使用`value-ref`属性 >
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <bean id="dataStructureBean" class="com.powernode.entity.DataStructure">

        <!--Map 分为简单类型、非简单类型value-->
        <property name="simpleMap">
            <map>
                <entry key="1" value="上海普陀区"/>
                <entry key="2" value="上海浦东新区"/>
                <entry key="3" value="上海长宁区"/>
            </map>
        </property>

        <property name="classMap">
            <map>
                <entry key="1" value-ref="goods1"/>
                <entry key="2" value-ref="goods2"/>
            </map>
        </property>
    </bean>
</beans>
注入Properties
> + java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合 > + 使用 标签嵌套 标签完成 >
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <bean id="dataStructureBean" class="com.powernode.entity.DataStructure">

        <property name="properties">
            <props>
                <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
                <prop key="username">root</prop>
                <prop key="password">root</prop>
            </props>
        </property>
    </bean>
</beans>
注入null和空字符串
> 注入空字符串使用:`****` 或者 `**value=""**`**** > > 注入null使用:`****` 或者 **不为该属性赋值** >
<?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="goods1" class="com.powernode.entity.Goods">
        <property name="name" value="香蕉"/>
    </bean>

    <bean id="goods2" class="com.powernode.entity.Goods">
        <property name="name" value="苹果"/>
    </bean>

    <bean id="dataStructureBean" class="com.powernode.entity.DataStructure">
        <!--空字符串-->
        <!--第一种写法-->
        <!--<property name="emptyString">-->
        <!--    <value/>-->
        <!--</property>-->

        <!--第二种写法-->
        <property name="emptyString" value="">
        </property>

        <!--null  第一种写法-->
        <!--<property name="nullString">-->
        <!--    <null/>-->
        <!--</property>-->

        <!--第二种写法 不写-->
    </bean>
</beans>
注入的值含有特殊字符
XML中由5个特殊字符,分别是`<`、`>`、`'`、`"`、`&`。以上五个特殊字符在XML中会被特殊对待,会被当做XML语法中的一部分进行解析,如果这些特殊字符直接出现在注入的字符串当中,就会报错。

解决方案

  1. 使用转义字符代替特殊符号
  2. 使用<font style="color:#DF2A3F;"><![CDATA[]]></font>,将含有特殊符号的字符串放到<font style="color:#DF2A3F;"><![CDATA[]]></font>当中。放在CDATA区的数据不会被XML文件解析器解析。但是注意,使用CDATA时,不能使用value属性,要使用value标签。
特殊字符转义字符
>>
<<
'
""
&&
<?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="mathBean" class="com.powernode.entity.MathBean">
        <!--当使用<![CDATA[]]> 时,只能使用value标签,不能使用value属性-->
        <property name="compare">
            <value><![CDATA[2<3]]></value>
        </property>
    </bean>

    <!--第二种方式-->
    <bean id="mathBean2" class="com.powernode.entity.MathBean">
        <property name="compare">
            <value>2 &lt; 3</value>
        </property>
    </bean>
</beans>
package com.powernode.entity;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/23 21:22
 */
public class MathBean {
    private String compare;

    public String isCompare() {
        return compare;
    }

    public void setCompare(String compare) {
        this.compare = compare;
    }

    @Override
    public String toString() {
        return "MathBean{" +
                "compare=" + compare +
                '}';
    }
}

    @org.junit.Test
    public void specialType(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beans-special-type.xml");

        MathBean mathBean = (MathBean) beans.getBean("mathBean");
        System.out.println(mathBean);
        //MathBean{compare=2<3}

        MathBean mathBean2 = (MathBean) beans.getBean("mathBean2");
        System.out.println(mathBean2);
        //MathBean{compare=2<3}
    }

P命名空间注入

1. P命名空间注入是为了简化set注入,本质上还是set注入,所以对应属性的Set方法依旧不可少 2. 使用P命名空间注入法需要添加 `xmlns:p="[http://www.springframework.org/schema/p"](http://www.springframework.org/schema/p")` 头 3. P命名注入法采用 `p:属性名="属性值"`的方法注入
package com.powernode.entity;

import java.util.Arrays;

public class Table {
    private String name;
    private Clazz clazz;
    // 一个订单中有多个商品
    private Goods[] goods;

    public Table() {
    }

    public Table(String name, Clazz clazz, Goods[] goods) {
        this.name = name;
        this.clazz = clazz;
        this.goods = goods;
    }

    public String getName() {
        return name;
    }

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

    public Clazz getClazz() {
        return clazz;
    }

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    public Goods[] getGoods() {
        return goods;
    }

    public void setGoods(Goods[] goods) {
        this.goods = goods;
    }

    @Override
    public String toString() {
        return "Table{" +
                "name='" + name + '\'' +
                ", clazz=" + clazz +
                ", goods=" + Arrays.toString(goods) +
                '}';
    }
}

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

  <bean id="goods1" class="com.powernode.entity.Goods">
    <property name="name" value="香蕉"/>
  </bean>

  <bean id="tableBean" class="com.powernode.entity.Table" p:name="chen" p:clazz="com.powernode.entity.Table" p:goods-ref="goods1">
  </bean>

</beans>
    @org.junit.Test
    public void PSetType(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beans-P-type.xml");

        Table tableBean = (Table) beans.getBean("tableBean");
        System.out.println(tableBean);
        // Table{name='chen', clazz=Clazz{name='com.powernode.entity.Table'}, goods=[Goods{name='香蕉'}]}

    }

C命名空间注入

1. c命名空间是简化构造方法注入的。 2. 使用c命名空间的两个前提条件: + 第一:需要在xml配置文件头部添加信息: - ` xmlns: c ="http://www.springframework.org/schema/c"` + 第二:需要提供构造方法。

3、使用c:_0 下标方式

        c:name 参数名方式
package com.powernode.entity;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/23 21:22
 */
public class MathBean {
    private String compare;

    public String isCompare() {
        return compare;
    }

    public MathBean(String compare) {
        this.compare = compare;
    }

    public void setCompare(String compare) {
        this.compare = compare;
    }

    @Override
    public String toString() {
        return "MathBean{" +
                "compare=" + compare +
                '}';
    }
}

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


  <bean id="MathBean" class="com.powernode.entity.MathBean" c:compare="sdasd">
  </bean>

</beans>
    @org.junit.Test
    public void CSetType(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("beans-C-type.xml");

        MathBean mathBean = (MathBean) beans.getBean("MathBean");
        System.out.println(mathBean);
        // MathBean{compare=sdasd}

    }

util命名空间

util命名空间的作用就是** 配置复用**。
  1. 使用时需要配置头部文件:
    • xmlns:util=“http://www.springframework.org/schema/util”
    • http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
  2. 标签名 —— util:类型

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


  <util:properties id="prop">
    <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
    <prop key="url">jdbc:mysql://localhost:3306/spring</prop>
    <prop key="username">root</prop>
    <prop key="password">root</prop>
  </util:properties>


  <bean id="dataSourceOne" class="com.powernode.entity.MyDataSource">
    <property name="properties" ref="prop"></property>
  </bean>

  <bean id="dataSourceTwo" class="com.powernode.entity.MyDataSource">
    <property name="properties" ref="prop"></property>
  </bean>
</beans>
@org.junit.Test
public void utilTest(){
    ApplicationContext beans = new ClassPathXmlApplicationContext("beans-util.xml");

    MyDataSource myDataSource1 = (MyDataSource) beans.getBean("dataSourceOne");
    System.out.println(myDataSource1);
    // MyDataSource{properties={password=root, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring, username=root}}

    MyDataSource myDataSource2 = (MyDataSource) beans.getBean("dataSourceTwo");
    System.out.println(myDataSource2);
    // MyDataSource{properties={password=root, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring, username=root}}

}

基于XML的自动装配

基于名称的自动装配
```java package com.powernode.Service;

import com.powernode.Dao.UserDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**

  • @Author:

  • @Description: TODO

  • @DateTime: 2024/9/19 15:19
    */
    public class UserServiceImpl implements UserService{

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    public UserDao aaa;

    public void setAaa(UserDao userDao){
    this.userDao = userDao;
    }

    @Override
    public void add() {
    logger.info(“add():userDao:{}”, userDao);
    userDao.add();
    }

    @Override
    public void update() {
    logger.info(“update():userDao:{}”, userDao);
    userDao.update();
    }
    }


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

    <!--根据名字进行自动装配-->
    <!--注意:自动装配也是基于set方式实现的。-->
    <bean id="userService" class="com.powernode.Service.UserServiceImpl" autowire="byName"/>

    <bean id="aaa" class="com.powernode.Dao.UserDaoImpl"/>
</beans>
@org.junit.Test
public void byNameTest(){
    ApplicationContext beans = new ClassPathXmlApplicationContext("spring-autowire.xml");

    UserService userService = (UserService) beans.getBean("userService");
    userService.add();
    userService.update();
}

✅UserService Bean中需要添加 **<font style="color:#DF2A3F;">autowire="byName"</font>**,表示进行名称装配

✅UserService类中有一个UserDao属性,而UserDao属性的名字是aaa,对应的set方法是setAaa(),正好和UserDao Bean的id是一样的。这就是根据名称自动装配。

基于类型的自动装配
```java package com.powernode.Dao;

public class AccountDao {
public void insert(){
System.out.println(“正在保存账户信息”);
}
}


```java
package com.powernode.Service;

import com.powernode.Dao.AccountDao;

public class AccountService {
    
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void save(){
        accountDao.insert();
    }
}
<?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">

  <!--byType表示根据类型自动装配-->
  <!--自动装配是基于set方法的-->
  <!--根据类型进行自动装配的时候,在有效的配置文件当中,某种类型的实例只能有一个。-->
  <bean id="accountService" class="com.powernode.Service.AccountService"
    autowire="byType"/>

  <bean class="com.powernode.Dao.AccountDao"/>
</beans>
    @org.junit.Test
    public void byNameTest(){
        ApplicationContext beans = new ClassPathXmlApplicationContext("spring-autowire.xml");

        UserService userService = (UserService) beans.getBean("userService");
        userService.add();
        userService.update();

        AccountService accountService = (AccountService) beans.getBean("accountService");
        accountService.save();

    }

如果根据类型装配(byType),在装配的时候都是基于set方法的,所以set方法是必须要提供的。当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个。

Spring引入外部属性文件

1、引入context命名空间

2、使用标签context

3、取值

以数据库配置为例,在实际开发中,数据库配置一般都是存放在properties/yaml文件中的,这样用户修改起来会更加的方便。当然可以。

第一步:实现一个数据源类,提供相关属性

package com.powernode.entity;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

/**
 * @Author: 
 * @Description: TODO
 * @DateTime: 2024/9/24 11:09
 */
public class MyJdbcSource implements DataSource {

    private String driver;
    private String url;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "MyJdbcSource{" +
        "driver='" + driver + '\'' +
        ", url='" + url + '\'' +
        ", username='" + username + '\'' +
        ", password='" + password + '\'' +
        '}';
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

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

    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

第二步:在类路径下新建dataSource.properties文件,并配置信息

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=root

第三步:在Spring配置文件中引入context命名空间

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

</beans>

第四步:在spring中配置使用dataSource.properties文件

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

  <!--
      引入properties文件:
          第一步:引入context命名空间
          第二步:使用context:property-placeholder的location属性来指定属性配置文件的路径
                   location默认从类的根路径下开始加载资源。
  -->
  <context:property-placeholder location="dataSource.properties"/>

  <!--配置数据源-->
  <bean id="dataSource" class="com.powernode.entity.MyJdbcSource">
    <property name="driver" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
  </bean>
</beans>

第五步:测试

@org.junit.Test
public void propertiesTest(){
    ApplicationContext beans = new ClassPathXmlApplicationContext("beans-dataSource.xml");

    MyJdbcSource jdbcSource = (MyJdbcSource) beans.getBean("dataSource");
    System.out.println(jdbcSource);
    // MyJdbcSource{driver='com.mysql.cj.jdbc.Driver', url='jdbc:mysql://localhost:3306/spring', username='root', password='root'}

}

注意点:${}默认会先加载windows里面的环境变量

这也是大多数数据库配置源都是采用xxx.xxx.jdbc.driver的形式,因为xml在解析${}能够找到对应的键值内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值