Spring(2)IOC基于xml的配置

371 阅读3分钟

目录

1.application.xml的配置

<?xml version="1.0" encoding="UTF-8"?>
<!--beans中添加了许多约束,即像url一样的代码,其作用就是约束该.xml文件中可以使用哪些标签-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
							http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
							http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
							http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">

    <!--开启注解扫描-->
    <context:component-scan base-package="com.qunar.事物"></context:component-scan>
    <!--注册user类-->
    <bean name="user" class="com.qunar.spring入门.pojo.User"></bean>

    <!--把数据库的配置信息写在一个独立的文件中,编译修改数据库的配置内容
      让spring知道jdbc.properties文件的位置
    -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--声明数据源DataSource,作用是连接数据库-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--set注入提供连接数据库信息-->
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="maxActive" value="${jdbc.maxActive}" />

    </bean>

    <!--SqlSessionFactory-->
    <!--声明的是mybatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory-->
    <bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!--set注入,把数据库连接池付给dataSource属性-->
        <property name="dataSource" ref="myDataSource"/>
        <!--mybatis主配置文件的位置
            configLocation属性是Resource类型,读取配置文件
            它的赋值使用的是value , 指定文件的路径,使用的是classpath:表示文件的位置
        -->
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>


    <!--创建 dao对象
        使用SqlSession的getMapper(StudentDao.class)
        MapperScannerConfigurer在内部调用getMapper()生成每个dao接口的代理对象
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定的是SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"/>

        <!--指定包名,包名是dao接口所在的包名
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行
            一次getMapper()方法,得到每个接口的dao对象
            创建好的dao对象放入到spring的容器中

            dao默认对象的名称:是接口名字的首字母小写
        -->
        <property name="basePackage" value="com.qunar"/>

        <!--多个包-->
        <!--<property name="basePackage" value="com.md.dao,com.md.dao2"/>-->
    </bean>
</beans>

2.bean标签

(1)作用:配置对象让spring来创建

默认情况使用无参构造函数创建对象,没有无参构造函数则创建不成功

(2)属性:

id:给对象在容器中提供一个唯一标识。用于获取对象。

class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。

scope:指定对象的作用范围。

  • singleton :默认值,单例的.
  • prototype :多例的.
  • request :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中.
  • session :WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中.
  • global session :WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session. init-method:指定类中的初始化方法名称。

destroy-method:指定类中销毁方法名称。

3.实例化bean的两种方式

第一种方式:使用默认无参构造函数

<!--在默认情况下:
它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>

第二种方式:使用工厂类的静态方法

/**
* 模拟一个静态工厂,创建业务层实现类
*/
public class StaticFactory {
	public static IAccountService createAccountService(){
	return new AccountServiceImpl();
	}
}
<!-- 此种方式是:
使用 StaticFactory 类中的静态方法 createAccountService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法
-->
<bean id="accountService"
class="com.itheima.factory.StaticFactory"
factory-method="createAccountService"></bean>

第三种方式:使用实例对象的方法

/**
* 模拟一个实例工厂,创建业务层实现类
* 此工厂创建对象,必须现有工厂实例对象,再调用方法
*/
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<!-- 此种方式是:
先把工厂的创建交给 spring 来管理。
然后在使用工厂的 bean 来调用里面的方法
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。
-->
<bean id="instancFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService"
factory-bean="instancFactory"
factory-method="createAccountService"></bean>

4.spring依赖注入

给spring容器中的bean对象属性注入初始值

第一种方式:使用构造函数注入

<!-- 使用构造函数的方式,给 service 中的属性传值
要求:
类中需要提供一个对应参数列表的构造函数。
涉及的标签:
constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称
=======上面三个都是找给谁赋值,下面两个指的是赋什么值的==============
value:它能赋的值是基本数据类型和 String 类型
ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value=" 张三 "></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>

第二种方式:使用set方法注入

<!-- 通过配置文件给 bean 中的属性传值:使用 set 方法的方式
涉及的标签:
property
属性:
name:找的是类中 set 方法后面的部分
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的
实际开发中,此种方式用的较多。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="test"></property>
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>

5.集合的注入

<!-- 注入集合数据
List 结构的:
array,list,set
Map 结构的
map,entry,props,prop
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<!-- 在注入集合数据时,只要结构相同,标签可以互换 -->
<!-- 给数组注入数据 -->
<property name="myStrs">
	<set>
		<value>AAA</value>
		<value>BBB</value>
		<value>CCC</value>
	</set>
</property>
<!-- 注入 list 集合数据 -->
<property name="myList">
	<array>
		<value>AAA</value>
		<value>BBB</value>
		<value>CCC</value>
	</array>
</property>
<!-- 注入 set 集合数据 -->
<property name="mySet">
	<list>
		<value>AAA</value>
		<value>BBB</value>
		<value>CCC</value>
	</list>
</property>
<!-- 注入 Map 数据 -->
<property name="myMap">
	<props>
		<prop key="testA">aaa</prop>
		<prop key="testB">bbb</prop>
	</props>
</property>
<!-- 注入 properties 数据 -->
<property name="myProps">
	<map>
		<entry key="testA" value="aaa"></entry>
		<entry key="testB"><value>bbb</value></entry>
	</map>
</property>

</bean>

6.lookup-method与replace-method

Spring的方法注入可分为两种

查找方法注入:用于注入方法返回结果,也就是说能通过配置方式替换方法返回结果。即我们通常所说的lookup-method注入。

替换方法注入:可以实现方法主体或返回结果的替换,即我们通常所说的replaced-method注入。

(一)lookup-method

(1)当单例对象依赖多例对象时,保证获得的多例对象不会存储在spring容器中,每个单例对象持有的多例对象是独立的

(2)对方法的返回结果进行增强

public class Car {

    //用于lookup-method注入
    public Taxi createTaxi(){
        System.out.println("car");
        Taxi taxi = new Taxi();
        taxi.setTaxiNmae("carCreate");
        return taxi;
    }

    private Taxi taxi;

    public Taxi getTaxi() {
        return taxi;
    }
    
    //setter注入
    public void setTaxi(Taxi taxi) {
        this.taxi = taxi;
    }
}

public class Taxi {
    private String taxiNmae;

    public void setTaxiNmae(String taxiNmae) {
        this.taxiNmae = taxiNmae;
    }

    public void say() {
        System.out.println("I am a Taxi..."+taxiNmae);
    }
}


public class lookupMethod与replaceMethod {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("lookupMethodAndRelapceMethod.xml");

        Car car1 = (Car) applicationContext.getBean("car");
        Car car2 = (Car) applicationContext.getBean("car");
        System.out.println("Car:singleton,所以car1==car2应该为" + (car1 == car2));

        Taxi taxi1 = car1.getTaxi();
        Taxi taxi2 = car1.getTaxi();
        System.out.println("Taxi:prototype,Car:singleton,未使用lookup-method注入所以taix1==taxi2应该为" + (taxi1 == taxi2));

        Taxi taxi3 = car1.createTaxi();
        Taxi taxi4 = car1.createTaxi();
        System.out.println("Taxi:prototype,Car:singleton,使用lookup-method注入所以taix3==taxi4应该为" + (taxi3 == taxi4));

        taxi1.say();
        taxi3.say();
    }
}
<bean id="taxi" class="com.qunar.spring入门.pojo.Taxi" scope="prototype"></bean>
    <bean id="car" class="com.qunar.spring入门.pojo.Car">
        <property name="taxi" ref="taxi"></property>
        <lookup-method name="createTaxi" bean="taxi" ></lookup-method>
    </bean>

输出结果

Car:singleton,所以car1==car2应该为true
Taxi:prototype,Car:singleton,未使用lookup-method注入所以taix1==taxi2应该为true
Taxi:prototype,Car:singleton,使用lookup-method注入所以taix3==taxi4应该为false
I am a Taxi...null
I am a Taxi...null

(二)replace-method

替换方法体及其返回值

注意,增强的方法必须实现MethodReplacer接口

public class OriginalDog {
    public void sayHello() {
        System.out.println("Hello,I am a black dog...");
    }

    public void sayHello(String name) {
        System.out.println("Hello,I am a black dog, my name is " + name);
    }
}

public class  ReplaceDog implements MethodReplacer {
    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("Hello, I am a white dog...");
        Arrays.stream(args).forEach(str -> System.out.println("参数:" + str));
        return obj;
    }
}

public class lookupMethod与replaceMethod {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("lookupMethodAndRelapceMethod.xml");

        System.out.println("++++++++++++++++++++++++++++++++++++++++++");
        OriginalDog originalDog = (OriginalDog) applicationContext.getBean("originalDog");
        originalDog.sayHello("sssss");
    }
}
<!-- ====================replace-method属性注入==================== -->
    <bean id="replaceDog" class="com.qunar.spring入门.pojo.ReplaceDog"></bean>
    <bean id="originalDog" class="com.qunar.spring入门.pojo.OriginalDog">
        <replaced-method name="sayHello" replacer="replaceDog">
            <arg-type match="java.lang.String"></arg-type>
        </replaced-method>
    </bean>

输出结果

Hello, I am a white dog...
参数:sssss

7.spring引入多个配置文件

(1)通过<import>标签引入其他的配置文件

 <import resource="配置文件2.xml"></import>
    <bean id="user" class="com.qunar.spring入门.pojo.User"></bean>

(2)直接在ApplictionContext中传入多个配置文件

 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("配置文件1.xml","配置文件2.xml");

8.spring 重名bean的覆盖问题