通过前两篇文章的学习,对spring有了初步的认识,并且应该认识到,spring的核心在于控制反转IOC和依赖注入DI
spring是怎么达到这个目标呢?
我们都已经知道理利用spring框架,依赖的注入由spring容器来进行,那么当然需要一些配置信息来告诉spring怎么注入。这就是spring元数据的配置(即bean的配置)。
综上,spring通过容器和元数据的配置来实现基本的功能。
通过本文达到,两个目标:
1.初步的认识spring容器。
2.初步认识spring元数据的配置
ApplicationContext
接口 org.springframework.context.ApplicationContext 代表了Spring IoC容器,它负责实例化、配置、组装beans. Spring通过读取元数据的配置进行以上的操作,元数据的配置有多种形式,包括xml、注解和JSR标准。
且Spring 提供了几种ApplicationContext的实现,如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext,顾名思义,它们读取基于xml的元数据配置。
程序示例
说明
下面通过一个简单的例子说明spring容器的简单用法和spring XMl元数据配置。
这个例子很简单,就是获取系统中的用户,然后打印出来。整个程序分为三各层次,模拟dao、service和客户端,客户端调用service,service调用dao。Service对dao的依赖由spring容器来管理。代码结构如下图:
代码
代码由客户端调用开始,一点点深入底层,其中的注释详细的说明了相关的要点。
首先是User类:
public class User { public int id; public String name; /** * @param id * @param name */ public User(int id, String name) { super(); this.id = id; this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
客户端
客户端由main函数调用模拟,代码如下:
package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.test.service.UserService; /** * @Description: 客户端首先初始化spring容器,然后从容器中获取benn调用其相应方法。和传统不一样的地方在于, * 业务对象UserService 的实例化不是由客户端通过new 来产生,而是直接从spring容器中获取。 * * 本示例例环境为eclipse */ public class TestMain { public static void main(String[] args) { /** * ApplicationContext代表spring容器,而ClassPathXmlApplicationContext是它的一个实现,它从类路径下读取相应的 * xml 元数据配置,并初始化容器。其中allbean.xml是相应的元数据配置 */ ApplicationContext context = new ClassPathXmlApplicationContext("allbean.xml"); //从容器中获取名称为 user 的 userService 对象,这个名称在配置文件之后配置。 UserService userService = context.getBean("user", UserService.class); System.out.println(userService.getUser()); //可以和传统方式相比较: // UserService user = new UserServiceIml(); // UserDao dao = new UserDaoImp(); // ((UserServiceIml)user).setUserDao(dao); // // System.out.println(user.getUser()); } }
allbean.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"> <!-- 此配置文件是spring 元数据的配置文件,根标签为 beans标签。 在这个标签下可以定义由Spring 管理的 bean,其定义形式如下被注释的地方所示: 基本的配置包括一个容器全局唯一的字符串id,和一个完全限定的类名。 但在这个例子中,有两个import标签,分别引入了另外两个 xml元数据配置文件。 这么做的好处是,不同的 bean定义对应相应的程序体系架构。 import标签导入的配置文件路径是相对路径,相对于当前文件。 路径前面可以与斜杠,但不建议这么做。如下示例不推荐使用 <import resource="/com/test/dao/dao.xml"/> 类似../的路径也不推荐使用 --> <import resource="com/test/dao/dao.xml"/> <import resource="com/test/service/service.xml"/> <!-- <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> --> </beans>
Service
Service层包含一个接口,一个实现类,一个Spring的xml元数据配置文件:
如下
/** * 接口 */ public interface UserService { public List<User> getUser(); } /** *实现类,有个字段引用了UserDao接口,其具体的业务逻辑调用 {@link UserDao#getUser()}实现 * *且有一个set方法,此set方法由spring 容器注入使用,如果没有回报错, *这是spring容器依赖注入的一种方法--setter注入 */ public class UserServiceIml implements UserService{ private UserDao userDao; @Override public List<User> getUser() { return userDao.getUser(); } public void setUserDao(UserDao userDao) { this.userDao = userDao; } }
Xml元数据配置如下,它定义了userServicebean,且定义了它的依赖:
<?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"> <!-- 定义了一个由Spring管理的 id为 user 类型为com.test.service.UserServiceIml 的 bean, property 标签用来定义setter 依赖。 name 属性 定义依赖的名称为 “userDao”(以便通过反射得到seeter方法),此名称和 UserServiceIml 的字段userDao对应。 ref属性定义此依赖引用了一个名称为 “userDao”的bean (这个bean在dao层定义) --> <bean id="user" class="com.test.service.UserServiceIml" > <property name="userDao" ref="userDao"></property> </bean> </beans>
Dao
Dao层定义了相应的 接口,实现类和 xml元数据配置,首先是接口和实现类:
public interface UserDao { public List<User> getUser(); } public class UserDaoImp implements UserDao{ @Override public List<User> getUser() { List<User> res = new ArrayList<User>(); User a = new User(1, "aa"); User b = new User(2, "bb"); res.add(a); res.add(b); return res; } }
然后是xml配置文件,定义了一个名称为userDao,实现类为com.test.dao.UserDaoImp 的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"> <bean id="userDao" class="com.test.dao.UserDaoImp"> </bean> </beans>
输出
运行客户端程序,输入如下,和预期一样:
总结
此文章简单的说明了Spring容器的用法和相关bean的配置。从一个极简单例子入手,自顶向下的进行剖析,并简单的分析了Spring的优点。当然本人目前水平有限,不当之处,欢迎指正。
另外,关于Spring bean的配置还有很多地方需要深入理解,不仅仅是Xml,还有注解、JSR以及他们的组合。bean的配置也包含其他方面,如基本数据类型、集合类型、生命周期、范围、容器扩展点等,而这些都属于spring的核心功能,需要逐步理解掌握,期待大家共同进步。