首页 > 技术文章 > Spring框架配置beans.xml扩展

sunfan1988 2013-12-08 21:36 原文

Spring学习笔记(二)

续Spring 学习笔记(一)之后,对Spring框架XML的操作进行整理

1 什么是IOC(DI)

 IOC = inversion of control   控制反转

 DI   = dependency injection 依赖注入

 

2 个人理解IOC(DI)的好处和作用

本来自己在代码NEW的东西改为由Spring来管理,体现了控制方的转变。

在由Spring管理的时候,需要用户通过配置bean来实现bean与bean的关联,依赖/注入为配置的方式,

好处何作用---》只需要管理配置文件就可以对类的进行管理-->灵活,可阅读性强。

 

本次笔记中的Spring的常用配置说明目录

1 Spring的注入类型

2 简单的属性注入

3 scope属性 

4 集合注入MAP,SET,LIST

5 自动装配 autowire

6 生命周期lazy-init  和初始毁灭方法的调用 init-method,destroy-method 

 

3 Spring 的注入类型

a setter注入(笔记一里已经实现,不再累述)

b 构造方法注入(沿用笔记一里的文件进行修改)

UserServiceImpl 类(存在构造函数)

package com.serviceImpl;

import com.dao.UserDao;
import com.daoImpl.UserDaoImpl;
import com.entity.User;

public class UserServiceImpl {
    private UserDao userDao;

    UserServiceImpl(UserDao userDao){//构造函数
        this.userDao = userDao;
    }
    
    public void add(User user) {
        userDao.save(user);
    }

    public void modify(User user) {
        userDao.update(user);
    }

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

beans.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">
        
  <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
  </bean>
  
  <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
  </bean>
  
  <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl">
     <constructor-arg><ref bean="userDaoImpl"/></constructor-arg>   <!-- 构造函数的注入配置-->
  </bean>
</beans>

执行UserServiceImplTest文件(无任何改动)

执行结果

testName-->testRemark  save --调用UserDaoImpl!

testName-->testRemark  update --调用UserDaoImpl!

总结,构造方法与setter方法注入实现起来差不多,只是调用的bean里面内部的标签不同而已

 

4 bean 标签里 使用Id和name的区别,这个不做研究了,查看了下文档,name只可以输入特殊字符"@#!@$!",没什么区别。

4 简单的属性注入

UserServiceImpl里面有个int类型的变量testInjectValue 未赋值

package com.serviceImpl;

import com.dao.UserDao;
import com.daoImpl.UserDaoImpl;
import com.entity.User;

public class UserServiceImpl {
    private UserDao userDao;
    int testInjectValue;//简单属性注入的测试

    UserServiceImpl(UserDao userDao){
        this.userDao = userDao;
    }
    
    public void add(User user) {
        userDao.save(user);
        System.out.println("testInjectValue = "+testInjectValue);
    }

    public void modify(User user) {
        userDao.update(user);
        System.out.println("testInjectValue = "+testInjectValue);
    }

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

    public int getTestInjectValue() {
        return testInjectValue;
    }

    public void setTestInjectValue(int testInjectValue) {
        this.testInjectValue = testInjectValue;
    }
    
}

我们通过beans.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">
        
  <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
  </bean>
  
  <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
  </bean>
  
  <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl">
     <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> 
     <property name="testInjectValue" value="34"></property>  <!--简单属性的注入-->
  </bean>
</beans>

执行测试文件

执行结果

testName-->testRemark save --调用UserDaoImpl!
testInjectValue = 34

testName-->testRemark update --调用UserDaoImpl!
testInjectValue = 34

总结.与接口的setter注入差不多,只是接口对应的是 bean="beanName", 这里是value="value"

 

5 bean里面的scope属性的运用

1 scope=singleton

beans.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">
        
  <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
  </bean>
  
  <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
  </bean>
  
  <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" scope="singleton"> <!-- 添加配置scope="singleton"-->
     <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> 
  </bean>
</beans>

2 scope=prototype

beans.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">
        
  <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
  </bean>
  
  <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
  </bean>
  
  <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" scope="prototype"> <!-- 添加配置scope="prototype"-->
     <constructor-arg><ref bean="userDaoImpl"/></constructor-arg> 
  </bean>
</beans>

3 分别配置scope=prototype/singleton和不配置scope 并执行UserServiceImplTest文件并查看结果

package com.serviceImpl.test;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.entity.User;
import com.serviceImpl.UserServiceImpl;

public class UserServiceImplTest {
    User user;

    @Before
    public void setUp() throws Exception {
        user = new User();
        user.setName("testName");
        user.setRemark("testRemark");
    }

    @Test
    public void testAdd() {
         ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
         UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
         UserServiceImpl UserServiceImpl2 = (UserServiceImpl)app.getBean("userServiceImpl");
         System.out.println(UserServiceImpl==UserServiceImpl2);
//         UserServiceImpl.add(user);//调用方法
    }

    @Test
    public void testModify() {
         ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
         UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
         UserServiceImpl UserServiceImpl2 = (UserServiceImpl)app.getBean("userServiceImpl");
         System.out.print(UserServiceImpl==UserServiceImpl2);
//         UserServiceImpl.modify(user);
    }
}

当scope=singleton时 执行结果为 true true

当scope=prototype时 执行结果为false false

当不配置scope时         执行结果为true true

总结 scope不做定义时,spring默认类的实现方式是为单例模式

只有scope=prototype时,spring会在每次调用时都去重新NEW一个新的类

 

6集合注入

UserServiceImpl 

package com.serviceImpl;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.dao.UserDao;
import com.daoImpl.UserDaoImpl;
import com.entity.User;

public class UserServiceImpl {
    private UserDao userDao;
    
    Map testMap;
    Set testSet;
    List testList;

    public void add(User user) {
        userDao.save(user);
        System.out.println(testMap.get("m"));
        System.out.println(testSet.iterator());
        System.out.println(testList.get(0));
    }

    public UserDao getUserDao() {
        return userDao;
    }

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

    public Map getTestMap() {
        return testMap;
    }

    public void setTestMap(Map testMap) {
        this.testMap = testMap;
    }

    public Set getTestSet() {
        return testSet;
    }

    public void setTestSet(Set testSet) {
        this.testSet = testSet;
    }

    public List getTestList() {
        return testList;
    }

    public void setTestList(List testList) {
        this.testList = testList;
    }
}

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

    <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
    </bean>

    <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
    </bean>

    <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl">
        <property name="userDao" ref="userDaoImpl"></property>
        <property name="testList">
            <list>
                <value>inject list</value>
            </list>
        </property>

        <property name="testMap">
            <map>
                <entry key="m" value="inject map" />
            </map>
        </property>
        <property name="testSet">
            <set>
                <value>inject set</value>
            </set>
        </property>
    </bean>
</beans>

执行UserServiceImplTest文件

执行结果

testName-->testRemark save --调用UserDaoImpl!
inject map
java.util.LinkedHashMap$KeyIterator@435a3a
inject list

总结 

1 这个还是和之前的注入差不多,要用的时候看一眼说明书即可。

 

7  自动装配(不是很常用)

autowire="byName"(不在代码实现了,用byType抛砖引玉)

autowire="byType"(注意:spring如果找到一个以上的具有同类型的bean会报错,所以我这里注释了userDaoImpl的bean)

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

<!--    <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">-->
<!--    </bean>-->

    <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
    </bean>

    <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" autowire="byType">
<!--        <property name="userDao" ref="userDaoImpl"></property>-->
    </bean>
</beans>

执行UserServiceImplTest文件

执行结果

testName-->testRemark  save --调用UserDaoImpl2!

总结

1 这个功能点不是很重要,按类型的话很多bean可能会起冲突,如果按名字的话,又对名字有很高的匹配要求,所以不是很实用。

2 另外在头部配置 autowire 的默认值后,可以使用beans的属性:default-autowire (基于这个功能不是很实用,所以没去试过)。

 

 

8 生命周期(配置bean的初始策略)

 lazy-init 

当不配置lazy-init=true时 applicationcontext被NEW出来的时候,所有的bean都会被初始化。

当配置了,这个bean就不会被初始化,除非方法调用。(系统启动特别慢时,可以考虑lazy-init =true 不然没什么太大意义

 init-method destroy-methd 方法的使用

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

    <bean id="userDaoImpl" class="com.daoImpl.UserDaoImpl">
    </bean>

    <bean id="userDaoImpl2" class="com.daoImpl.UserDaoImpl2">
    </bean>

    <bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl" init-method="init" destroy-method="destroy" lazy-init="true">
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
</beans>

UserServiceImpl

package com.serviceImpl;


import com.dao.UserDao;
import com.daoImpl.UserDaoImpl;
import com.entity.User;

public class UserServiceImpl {
    private UserDao userDao;

    public void add(User user) {
        userDao.save(user);
    }
    
    public void init(){//初始方法
        System.out.println("init");
    }

    public void destroy(){//销毁方法
        System.out.println("destory");
    }

    public UserDao getUserDao() {
        return userDao;
    }

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

UserServiceImplTest

package com.serviceImpl.test;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.entity.User;
import com.serviceImpl.UserServiceImpl;

public class UserServiceImplTest {
    User user;

    @Before
    public void setUp() throws Exception {
        user = new User();
        user.setName("testName");
        user.setRemark("testRemark");
    }

    @Test
    public void testAdd() {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
         UserServiceImpl UserServiceImpl = (UserServiceImpl)app.getBean("userServiceImpl");
         UserServiceImpl UserServiceImpl1 = (UserServiceImpl)app.getBean("userServiceImpl");
         UserServiceImpl.add(user);//调用方法
         app.destroy();//在WEB应用里会自动调用,这里直接手动调用了。
    }

}

执行UserServiceImplTest文件

执行结果

init
testName-->testRemark save --调用UserDaoImpl!

destory

总结

 init-method destroy-methd 方法的使用需要注意别与scope=prototype并用,用上面的代码测试了一下,结果是init被调用了2次,但是destroy未被调用过,不解。

 

结束总结

Spring配置文件提供了以下的配置手法及管理策略,对项目的管理能有不少的帮助,学习下来较为实用的还是setter注入。

1 Spring的注入类型

2 简单的属性注入

3 scope属性 

4 集合注入MAP,SET,LIST

5 自动装配 autowire

6 生命周期lazy-init  和初始毁灭方法的调用 init-method,destroy-method 

推荐阅读