上篇博客大致了解了Spring的一些知识,这次我们通过一个例子来了解Spring常用的两种注入方式构造器注入和setter注入。先看例子。
因为spring是一个轻量级的框架与创建的项目类型无关,故而我们创建一个java项目即可。
1. 示例演示
新建一个Java Project
建好的目录结构如下:
很简单,此时我们需要为其添加相关的类和组件从而使得其变得丰富,添加完后的目录结构如下图:
其中划线部分是我引入的关于Spring,以及单元测试,日志等等相关的jar包,如果你的程序出现问题,尤其是以java.lang.NoClassDefFoundError为首相关的错误,一般是缺少相关的jar,引入相关的jar即可。
建立一个数据访问层的类,这里我们作为例子没有与数据库交互,主要是为了讲解Spring的相关,与hibernate以及Struts结合起来的使用我们在后面会讲到的。
UserDao(数据访问层的接口)
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>package com.bjpowernode.spring.dao;
public interface UserDao {
public void addUser(String username, String password);
}</strong></span>
添加相应的实现这里我们采用Oracle和mysql两种实现,这样可以对比在Spring容器中数据库的灵活切换。
UserDao4MySqlImpl(UserDao4OracleImpl)
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>public class UserDao4MySqlImpl implements UserDao {
public void addUser(String username, String password) {
System.out.println("UserDao4MySqlImpl.addUser()");
}
}
public class UserDao4OracleImpl implements UserDao {
public void addUser(String username, String password) {
System.out.println("UserDao4OracleImpl.addUser()");
}
}</strong></span>
建立完数据访问层,再建立相应的服务层
服务层接口(UserManager)
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>public interface UserManager {
public void addUser(String username, String password);
}</strong></span>
实现类(UserManagerImpl)
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>package com.bjpowernode.spring.manager;
import com.bjpowernode.spring.dao.UserDao;
public class UserManagerImpl implements UserManager {
private UserDao userDao;
// public UserManagerImpl(UserDao userDao) {
// this.userDao = userDao;
// }
public void addUser(String username, String password) {
userDao.addUser(username, password);
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}</strong></span>
添加一个测试类Client
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>public class Client {
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext(
"applicationContext.xml");
// ApplicationContext factory = new
// ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager) factory.getBean("userManager");
// UserManager userManager = new UserManagerImpl(new
// UserDao4MySqlImpl());
userManager.addUser("张三", "123");
}
}</strong></span>
核心的配置文件(applicationContext.xml)
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><?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: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-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="userDao4Mysql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl"/>
<bean id="usrDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<!--
<constructor-arg ref="userDao4Mysql"/>
-->
<!--
<constructor-arg ref="usrDao4Oracle"/>
-->
<property name="userDao" ref="usrDao4Oracle"/>
</bean>
</beans></strong></span>
2. 示例知识点讲解
配置文件的读取方式
上篇博客我们已经讲解了存在两种方式读取配置文件,一个是使用BeanFactory,而另一种使用ApplicationContext。
BeanFactory基本的工厂解析,管理,实例化所有容器内的bean的接口,spring中所有解析配置文件的类都直接或者间接实现该接口。
ApplicationContext接口implements BeanFactory
创建对象的特点: BeanFactory在解析配置文件时并不会初始化对象,只有在使用对象时(getBean())才会对该对象进行初始化;ApplicationContext在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程。
注入的方式setter和构造器
无论是构造器注入还是setter注入,都是一种依赖关系的注入,也就是将应用程序代码间的关系在配置文件中进行了描述,这里只是描述对象间的依赖关系或者业务逻辑的关系并不包含,但是并不创建相应的对象。
好处就是应用DI原则后,代码将更加清晰。而且当bean自己不再担心对象之间的依赖关系(甚至不知道依赖的定义指定地方和依赖的实际类)之后,实现更高层次的松耦合将易如反掌。DI主要有两种注入方式,即Setter注入和构造器注入。
构造器注入
基于构造器的DI通过调用带参数的构造器来实现,每个参数代表着一个依赖。
在上述代码的体现是:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>public class UserManagerImpl implements UserManager {
private UserDao userDao;
public UserManagerImpl(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(String username, String password) {
userDao.addUser(username, password);
}
</strong></span>
在配置文件中配置:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="usrDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<constructor-arg ref="userDao4Mysql"/>
</bean>
</strong></span>
延伸知识:
对于类型匹配没有错误的,如下面的:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>package examples;
public class ExampleBean {
// No. of years to the calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
</strong></span>
该bean的构造参数类型已知,匹配也没有问题(跟前面的例子一样)。但是当使用简单类型时,比如<value>true<value>,Spring将无法知道该值的类型。不借助其他帮助,他将无法仅仅根据参数类型进行匹配。
此时我们需要使用的是构造器参数类型匹配或者是构造参数索引。具体如下:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
这是根据的参数类型。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
</strong></span>
这是根据的索引。
Setter注入
通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的DI。
在代码中的使用:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong>public class UserManagerImpl implements UserManager {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(String username, String password) {
userDao.addUser(username, password);
}
</strong></span>
在配置文件中的配置:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="usrDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<property name="userDao" ref="usrDao4Oracle"/>
</bean>
</strong></span>
配置访问数据库的数据源
除了上述的setter属性注入和构造器注入之外,我们还可以使用属性进行相关的数据源的配置。
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/Spring_first</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>root</value>
</property>
</bean></strong></span>
也可以使用较为简洁的方式:
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ Spring_first "/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</strong></span>
数据访问层实现方式的灵活切换
<span style="font-family:Microsoft YaHei;font-size:14px;"><strong><bean id="userDao4Mysql" class="com.bjpowernode.spring.dao.UserDao4MySqlImpl"/>
<bean id="usrDao4Oracle" class="com.bjpowernode.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjpowernode.spring.manager.UserManagerImpl">
<!--
<constructor-arg ref="userDao4Mysql"/>
-->
<!--
<constructor-arg ref="usrDao4Oracle"/>
-->
<property name="userDao" ref="usrDao4Oracle"/>
</bean>
</strong></span>
我们只是需要更改ref指定的bean的唯一标识符id的值,即可实现灵活的切换,这样是不是很方便啊。
3. 小结
讲解完这些是不是明朗了很多呢!下篇咱们来说说容器是如何来管理你的bean,敬请期待~