程序员技术栈Java 杂谈每日一篇Java

Spring(一)-Spring IoC和DI容器

2018-08-23  本文已影响0人  sixleaves

1.Spring简介

Spring是J2EE开发中一个很重要的框架。它主要用来解决下面两个问题。

根据Spring解决的问题,和其对应的专业术语。我们也说Spring是一个轻量级的DI/IoCAOP容器开源框架, 其提倡最小侵入式管理应用中的代码,意味着我们可以随时卸载和安装Spring.

接下去我们需要理解下Spring以下的专业术语,我就不抄写网络上的术语内容,并不是那么通俗,以我的理解如下。

1.2 Spring术语

1.3 Spring的框架构架

之所以要了解Spring构架是在学习之前我们要对一样事务大体的骨架有一个了解。在介绍Spring的构架之前,我们简要的说下Spring的优势。

Spring的优势

构架

从上之下。主要分为

Spring框架版本

这里简要介绍下Spring各个版本的变化。其中Spring2.5是变化最大的一个版本,其已经完成了大部分Spring的核心功能。而后续版本都是在其上增加新的语法支持等。

介绍完Spring的一些基础常识,我们看是以Spring来写一个最简单的HelloWorld,学习基于Spring搭建应用的基本步骤。

2. 基于Spring如何编写程序

关于Spring插件

如果不是用Spring官方提供的Eclipse。需要自己安装SIS插件.

2.1 基于Spring的HelloWorld编写步骤

目录结构

测试代码

public class HelloWorldTest {
    
    @Test
    public void testHelloWorld() {
        
            Resource resource = new ClassPathResource("com/sweetcs/_01helloworld/hello.xml");
            BeanFactory beanFactory = new XmlBeanFactory(resource);
            HelloWorld helloWorld = beanFactory.getBean("helloWorld", HelloWorld.class);
            helloWorld.say();
    }
}

输出

可以看到我们使用IoC容器成功的获取到对应的Bean对象,并调用其say方法,输出Hello Spring.

2.2 Spring基本配置

使用Spring编写完第一个HelloWorld演示程序,接下来我细致的分享下Spring基本的配置方式

2.2.1 bean的id和name

在Spring的配置文件中, 也就是配置bean的文件中.我们需要给Bean配置属性。其中比较常用,用来定位Bean的用两种方式,一种是id一种是name.

id方式
<?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="helloWorld" class="com.sweetcs._01helloworld.HelloWorld"></bean>
</beans>

测试代码

    @Test
    public void testHelloWorldByID() {
        
            Resource resource = new ClassPathResource("com/sweetcs/_01helloworld/hello.xml");
            BeanFactory beanFactory = new XmlBeanFactory(resource);
            HelloWorld helloWorld = beanFactory.getBean("helloWorld", HelloWorld.class);
            helloWorld.say();
    }

ID方式输出

name方式
<?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="helloWorld" class="com.sweetcs._01helloworld.HelloWorld"></bean> -->
    <bean name="helloWorld,helloWorld2,helloWorld3" class="com.sweetcs._01helloworld.HelloWorld"></bean>
</beans>

测试代码

    @Test
    public void testHelloWorldByName() {
        
            Resource resource = new ClassPathResource("com/sweetcs/_01helloworld/hello.xml");
            BeanFactory beanFactory = new XmlBeanFactory(resource);
            HelloWorld helloWorld = beanFactory.getBean("helloWorld", HelloWorld.class);
            HelloWorld helloWorld2 = beanFactory.getBean("helloWorld2", HelloWorld.class);
            HelloWorld helloWorld3 = beanFactory.getBean("helloWorld3", HelloWorld.class);
            
            System.out.println(helloWorld == helloWorld2);
            System.out.println(helloWorld2 == helloWorld3);
    }

输出

ID和name的区别

2.3 模块化xml配置文件

如果我们项目中有很多的bean需要注册, 那么这时候如果还只是用一个bean的配置文件,那这个文件配置的bean会爆炸性的增长, 这带来的后果就是十分的难以维护这个配置文件。这个时候我们可以将xml进行拆分, 拆分多个xml文件。一般项目都是按模块划分的,我们可以每个模块下都配置一个xml文件。最后再通过一个统一xml文件,将这些xml文件引入。

引入其他XML配置文件

import元素

使用import元素我们可以将其他的xml配置文件导入。其使用resource属性代表要导入的文件路径,并且提供了classpath:file:协议分别表示从classpath路径寻找和从文件系统的路径寻找.

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

    <!-- 导入_01helloworld包下的配置文件 -->
    <import resource="classpath:com/sweetcs/_01helloworld/hello.xml"/>

</beans>

对应的测试类代码
注解的意思可以先忽略,看完1.6就明白

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class ApplicationContextTest {
    
    @Autowired
    BeanFactory ioc;
    
    @Test
    public void testHelloSpring() {
        HelloWorld bean = ioc.getBean("helloWorld", HelloWorld.class);
        bean.say();
    }   
}

2.4 Spring中的测试

问题:在编写Spring的测试用例中, 我们直接使用Spring提供的Test。因为该Test是包含在容器中, 我们不用每一次都创建容器,关闭容器, 这对系统开销十分大。

2.4.1 测试步骤

// 告诉JVM,Spring测试运行于JVM上.而不是让Junit运行于JVM上.
@RunWith(SpringJUnit4ClassRunner.class)
// 告诉Spring去哪里寻找配置文件.
@ContextConfiguration("classpath:com/sweetcs/_02springtest/HellWoldTest.xml")
public class HelloWorldTest {
    // 自动装配IoC容器
    @Autowired
    BeanFactory ioc;
    
    @Test
    public void testHelloSpring() {
        
        HelloWorld helloWorld =  ioc.getBean("helloWorld", HelloWorld.class);
        helloWorld.say();
    }
}

配置文件命名的小技巧

@ContextConfiguration也可以不用指定配置文件路径, 如果不指定,其默认配置文件所在的类文件同一级目录下,且该配置文件名类名-context.xml.对于上述程序可以的配置文件名就可以改成HellWoroldTest-context

上述主要讲了

接下来我们要比较系统的介绍下IoC容器的内容。

3.IoC

IoC容器, 即Inversion Of Control, 中文翻译就是反转控制。IoC容器反转了哪些控制呢?其实IoC是一种思想,这种思想被引入软件工程学中, 主要是为了解决大型软件项目中的耦合过深问题。

3.1 思想

传统的思维

传统的思维下,我们需要哪个对象就去new一个。比如下面的代码。

public class EmployeeService {
    private IEmployeeDAO employeeDAO = new EmployeeDAO();
}

这中代码本省写得并没有错,但是随着软件复杂度的增加, 你可能导出都存在这种代码,对于EmployeeService来说它就依赖EmployeeDAO.如果采用这种方式,可想而知,项目中会存在很多复杂的依赖,而且这些依赖有的又是重复引用的.这会导致,其中一个依赖要是存了问题,整个软件系统就无法正常的运行。
如下图,是我在网络上找的一张图,传统软件开发思维如下。导致的问题可想而知。齿轮之间相互耦合太强,牵一发而动全身。

IoC反转控制思想

传统的软件设计是我们需要什么对象需要我们自己去创造,如上分析这随着软件复杂度增加,对于系统的维护和变更是十分困难的,因为存在太多耦合。
IoC的思想
IoC的思想是能不能把这种主动的控制权转交出来,当我们需要某个对象的时候才让"第三方"帮我们注入我们需要的对象。这就解除了类之间的耦合关系,类于类之前的联系需要通过这个中间容器即IoC容器来桥接。

如下图, 只要遵守这个"第三方"的规则,所有的齿轮都能够转动。这个第三方就相当于一个粘合剂,将所有齿轮"粘合"起来,保证整个系统的运转。

这种控制权颠倒过来的设计, 我们就是把它称为“控制反转”。通过这种设计,我们可以在Spring中很方便的扩充功能,而且还能让类之间解除耦合。

说了那么多我们先来看下Spring中IoC容器容器如何创建BeanBean如何实例化Bean的作用域已经Bean的初始化和销毁方法

3.2 IoC容器

获取IoC容器的方式有两种。一种是BeanFactory提供了最基本的IoC功能。一种是ApplicatioinContext, 基于BeanFactory扩展了更强的功能.

3.2.1 基于ApplicationContext创建IoC容器(Spring容器)

基于BeanFactory的方式在HelloWorld中已经介绍过, 我们就简单介绍下,基于ApplicatioinContext创建Spring容器的方式。由于ApplicationContext也是一个接口,所以我们只能找其实现类。

通过查看类继承结构如下图,可以发现有如下两个类。

3.3 Bean创建时机研究

ApplicatioinContext和BeanFactory对bean的创建时机并不是相同的,我们来研究下他们有什么区别。之所以以下代码不采用Spring提供的Test来自动装配IoC容器,是因为如果使用SpringTest,它会自动加载所有Bean.就看不出ApplicationContext创建Bean的时机和BeanFactory的区别。

以下代码省略了转交控制权的步骤,需要配置xml,可以参考上面的配置步骤。

3.3.1 基于BeanFactory的Bean创建时机研究

    @Test
    public void testCreateWithBeanFactory() {
        Resource resource = new ClassPathResource("com/sweetcs/_03ioc/BeanCreateTest-context.xml");
        BeanFactory ioc = new XmlBeanFactory(resource);
        User user = ioc.getBean("user", User.class);
        System.out.println(user);
        /*  输出
            User 构造器被调用,正在初始化User对象
            User [name=SweetCS]
         */
    }
    
    @Test
    public void testCreateWithBeanFactory2() {
        Resource resource = new ClassPathResource("com/sweetcs/_03ioc/BeanCreateTest-context.xml");
        BeanFactory ioc = new XmlBeanFactory(resource);
        /*
         * 无任何输出
         */
    }

使用BeanFacory方式,Bean只会在需要的时候才创建

3.3.2 基于ApplicationContext的Bean创建时机研究

    
    @Test
    public void testCreateWithApplicationContext() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("com/sweetcs/_03ioc/BeanCreateTest-context.xml");
        User bean = ctx.getBean("user", User.class);
        System.out.println(bean);
        /*  输出
            User 构造器被调用,正在初始化User对象
            User [name=SweetCS]

         */
    }
    
    @Test
    public void testCreateWithApplicationContext2() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("com/sweetcs/_03ioc/BeanCreateTest-context.xml");
        // 输出 User 构造器被调用,正在初始化User对象
    }   

运行程序后使用ApplicationContext的方式,无论有没有取获取Bean,Bean都会在容器启动的时候被创建

BeanFactory和ApplicationContext的应用场景

  • ApplicatioinContext会一次性将所有Bean的创建出来,主要是为了优化服务端的性能,主用应用于Web后端开发
  • BeanFacory只会在需要使用Bean的时候在创建, 主要用在客户端开发。因为客户端直接面向用户,关注用户体验。不能再一启动创建大量对象,让应用卡顿半天。

3.3.3 能否配置延迟创建

其实这个需求,一般不回用到。对于我们做后端开发的来说, 最常用的是ApplicationContext, 如果要让其延迟加载Bean也是可以。有两种配置方式。

3.4 Bean的实例化方式

之所以要聊Bean的实例化方式,是因为我们可能会在不同的情况下需要使用不同的方式,让Spring帮我们注入对象。所以我们需要来研究下让Spring帮我们注入对象的四种方式, 其对应的就是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">

<!-- 1.最标准的方式,通过无参够照器方式创建 -->
    <bean id="user" class="com.sweetcs._04beaninstance.construtor.User"></bean>
</beans>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class BeanInstanceTest {
    
    @Autowired
    ApplicationContext ctx;
    
    @Test
    public void testInstanceBeanWithNoArgConstrutor() {
        User bean = ctx.getBean("user", User.class);
        System.out.println(bean);
    }   
}

输出

通过静态工厂实例化方式

其主要解决一些系统留下来的问题。例如有可能你接触的项目并不是通过最标准的创建Bean的方式创建,它可能都是使用静态工程创建,那我们就应该在接入Spring的时候,为了兼容性,使用静态工厂实例化方式。
SomeBean2StaticFactory
配置bean,id, class ,factory-method

    
    @Test
    public void testInstanceBeanWithStaticFactory() {
        SomeBean someBean = ctx.getBean("someBean", SomeBean.class);
        System.out.println(someBean);
    }

输出

通过实例工厂实例化方式

SomeBean2

package com.sweetcs._04beaninstance.instance_factory;
public class SomeBean2 {

}

SomeBean2Factory

package com.sweetcs._04beaninstance.instance_factory;
public class SomeBean2Factory {
    public SomeBean2 getSomeBean2() {
        return new SomeBean2();
    }
}

转交控制权

    <!-- 3.通过实例工厂实例化 -->
    <bean id="someBean2Factory" class="com.sweetcs._04beaninstance.instance_factory.SomeBean2Factory"></bean>
    <bean id="someBean2" factory-bean="someBean2Factory" factory-method="getSomeBean2"></bean>

测试用例

    @Test
    public void testInstanceBeanWithInstanceFactory() {
        SomeBean2 someBean2 = ctx.getBean("someBean2",SomeBean2.class);
        System.out.println(someBean2);
    }

需要new出这个工厂
先要转交实例工厂对象创建权
再要转交Bean对象创建权

实现FacotryBean接口实例化。实例工厂的变种,主要为了集成其他框架。

如果发现了这个对象是实现这个接口,Spring容器会自动条用getObject方法返回创建的对象。

package com.sweetcs._04beaninstance.facotry_bean;

import org.springframework.beans.factory.FactoryBean;

public class MyBean {
}

package com.sweetcs._04beaninstance.facotry_bean;

import org.springframework.beans.factory.FactoryBean;

public class MyBeanFactory implements FactoryBean<MyBean>{

    @Override
    public MyBean getObject() throws Exception {
        // TODO Auto-generated method stub
        return new MyBean();
    }

    @Override
    public Class<?> getObjectType() {
        // TODO Auto-generated method stub
        return MyBean.class;
    }

    @Override
    public boolean isSingleton() {
        // TODO Auto-generated method stub
        return false;
    }
    
}

测试用例

    @Test
    public void testInstanceBeanWithImplementsFactoryBean() {
        MyBean myBean = ctx.getBean("myBean", MyBean.class);
        System.out.println(myBean);
    }

输出

3.5 Bean的作用域

Bean的作用域研究表示Bean可以存活多久, Bean的标签里有一个scope属性,要来表示Bean的作用域。这边只介绍用得最多的两种方式singleton(单例)和prototype(多例)。

默认方式

<?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="myBean" class="com.sweetcs._05beanscope.MyBean"></bean>
    
</beans>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MyBeanTest {
    
    @Autowired
    ApplicationContext ctx;
    
    @Test
    public void testDefaultScope() {
        
        MyBean myBean = ctx.getBean("myBean", MyBean.class);
        MyBean myBean2 = ctx.getBean("myBean", MyBean.class);
        MyBean myBean3 = ctx.getBean("myBean", MyBean.class);
        
        System.out.println(myBean + "\n" + myBean2 + "\n" + myBean3);
    }
}

输出

Singleton方式

更改bean的配置的,添加scope属性为singleton

    <bean id="myBean" class="com.sweetcs._05beanscope.MyBean" scope="singleton"></bean>

再运行刚才的用例,输出

prototype方式

更该bean的配置为prototype

    <bean id="myBean" class="com.sweetcs._05beanscope.MyBean" scope="prototype"></bean>

所有作用域的总结

最常用的是singleton和prototype作用域。其他的可以参考以下

作用域 描述
singleton 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。
prototype 该作用域将单一 bean 的定义限制在任意数量的对象实例。
request 该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。
session 该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
global-session 该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。

3.6 Bean的初始化和销毁方法

bean标签中提供了init-method属性和destory-method属性。分别会在bean创建之前调用,在bean销毁之前做收尾操作。

3.6.1 DataSource需要回收

比如DataSource最终都需要关闭资源, 在Bean销毁之前,都要调用close方法。

MyDataSourceBean

package com.sweetcs._06bean_init_destory;

public class MyDataSourceBean {
    
    public void doingSomeWork() {
        
        System.out.println("处理业务逻辑");
    
    }
    
    
    public void init() {
        
        System.out.println("初始化配置,准备连接数据库");
    }
    
    
    public void close() { 
        System.out.println("释放connection");
    }
    
}

转交控制权给Spring容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="myDataSource" class="com.sweetcs._06bean_init_destory.MyDataSourceBean" 
    init-method="init" destroy-method="close"></bean>
</beans>

MyDataSourceBeanTest

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration
public class MyDataSourceBeanTest {
    
    @Autowired
    ApplicationContext ctx;
    
    @Test
    public void testCreateMyDataSourceBean() {
        MyDataSourceBean dataSource = ctx.getBean("myDataSource", MyDataSourceBean.class);
        dataSource.doingSomeWork();
    }
}

输出

3.6.2 对于多例无效

如果Bean标签的scope属性配置成scope="prototype"。则容器不负责销毁控制,而且这个bean也不会放入Spring容器里取管理, 而是一创建就交给程序员,让程序员自己去负责。

    <bean id="myDataSource" class="com.sweetcs._06bean_init_destory.MyDataSourceBean" 
    init-method="init" destroy-method="close" 
    scope="prototype">
        
    </bean>

4.DI

DI又称为依赖注入.DI是IoC思想的一种实现,在Spring容器中就采用了DI技术来实现IoC, 即采用DI实现了反转控制。所以我们要来探讨下如何注入,注入的几种方式。记下来我们主要来研究自动装配属性注入构造器注入属性占位符的使用

4.1 自动装配

自动装配Spring中主要提供了两种方式。如下

基于XML的自动装配

我们创建两个类分别是ABean和CBean,让ABean依赖于CBean.代码如下

<?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="aBean" class="com.sweetcs._07di.autowise_xml.ABean" autowire="byType"></bean>
    <bean id="cBean" class="com.sweetcs._07di.autowise_xml.CBean"></bean>
</beans>

ABean


public class ABean {
    
    private CBean cBean;
    
    public void setcBean(CBean cBean) {
        this.cBean = cBean;
    }

    @Override
    public String toString() {
        return "ABean [cBean=" + cBean + "]";
    }   
}

CBean

public class CBean {

}

测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AutoWiseWithXMLTest {
    
    @Autowired
    ApplicationContext ctx;
    
    @Test
    public void testAutoWiseWithXML() {
        
        ABean bean = ctx.getBean("aBean", ABean.class);
        System.out.println(bean);
        
    }
}

输出

如上输出, 基于XML方式自动装配.自动将CBean注入到了ABean当中。使用的是byType的方式,其实还可以使用byName的方式。下面说下二者区别

byName和byType的区别

4.2 注入值

4.2.1 setter注入

一般我们不会在xml中使用自动装配,应用这样很难看出这个bean有哪些属性。取而代之的是有两种方法

注入简单类型-使用字符串

    <bean id="employee" class="com.sweetcs._07di.property.Employee">
        <property name="name" value="SweetCS"></property>
        <property name="url"  value="http://www.baidu.com"></property>
        <property name="age" value="1"></property>
    </bean>

测试用例

public class Employee {
    

    private String name;
    private URL url;
    private Integer age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public URL getUrl() {
        return url;
    }
    public void setUrl(URL url) {
        this.url = url;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }   
    

    @Override
    public String toString() {
        return "Employee [name=" + name + ", url=" + url + ", age=" + age + "]";
    }
}
    @Test
    public void testDIWithProperyMethod() {
        
        Employee employee = ctx.getBean("employee", Employee.class);
        System.out.println(employee);
        
    }

注入引用类型

public class EmployeeDAO {
    public void save() {
        System.out.println("开始持久化数据到数据库");
    }
}

public class EmployeeService {
    private EmployeeDAO employeeDAO;

    public void setEmployeeDAO(EmployeeDAO employeeDAO) {
        this.employeeDAO = employeeDAO;
    }

    @Override
    public String toString() {
        return "EmployeeDAO [employeeDAO=" + employeeDAO + "]";
    }
    
    public void save() {
        employeeDAO.save();
    }
}

xml配置

    <bean id="employeeService" class="com.sweetcs._07di.property.EmployeeService" autowire="byType"></bean>
    <bean id="employeeDAO" class="com.sweetcs._07di.property.EmployeeDAO"></bean>

注入集合类型


public class CollectionBean {
    
    private Set set;
    private List list;
    private String[] array;
    private Properties properties;
    private Map map;
    
    
    public void setArray(String[] array) {
        this.array = array;
    }


    public void setProperties(Properties p) {
        this.properties =p;
    }
    

    public void setSet(Set set) {
        this.set = set;
    }
    public void setList(List list) {
        this.list = list;
    }

    public void setMap(Map map) {
        this.map = map;
    }
    @Override
    public String toString() {
        return "CollectionBean [set=" + set + ", list=" + list + ", arrayList=" + array + ", map=" + map + "]";
    }
    
}

xml配置

    
    <bean id="collectionBean" class="com.sweetcs._07di.property.CollectionBean">
        <property name="set">
            <set>
                <value>"1"</value>
                <value>"2"</value>
                <value>3</value>
            </set>
        </property>
        
        <property name="list">
            <list>
                <value>"1"</value>
                <value>"2"</value>
                <value>3</value>
            </list>
        </property>
        
        <property name="array">
            <array>
                <value>"1"</value>
                <value>"2"</value>
                <value>"3"</value>
            </array>
        </property>
        
        <property name="properties">
            <value>
                key1=value1
                key2=value2
                key3=value3
            </value>
        </property>
        
        <property name="map">
            <map>
                <entry key="key1" value="value1"></entry>
                <entry key="key2" value="value2"></entry>
                <entry key="key3" value="value3"></entry>
            </map>
        </property>
        
    </bean>

4.2.2 构造器注入

构造器注入其实和属性注入差不多, 主要有两个差别,具体就不演示了。

4.3 property place holder(配置数据库连接池)

属性占位符是十分有用的一个功能。开发中一般我们都将有关数据库的配置做成一个配置文件,方便和运维人员解耦,运维人员只要拿着配置文件取做部署,无需关心程序员的代码实现细节。

步骤

XML配置, 转交控制权

    <context:property-placeholder location="classpath:config.properties"/>
    <bean id="ds" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="initialSize" value="${jdbc.initialSize}"></property>
        <property name="maxActive" value="${jdbc.maxActive}"></property>
        <property name="minIdle" value="${jdbc.minIdle}"></property> 
    </bean>

测试用例

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration
public class DruidCreateTest {
    
    @Autowired
    ApplicationContext ctx;
    
    @Test
    public void testGetConnWithDruid()  {
        
        DruidDataSource ds = ctx.getBean("ds", DruidDataSource.class);
        Connection connection = null;
        try {
            connection = ds.getConnection();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(connection);
    }
}

输出

上一篇下一篇

猜你喜欢

热点阅读