今天开始spring的系列文章,由于我也是边学边写,如果有不对的地方还请指出来,大家一起学习共同进步。
在进行Spring的第一篇讲解前首先搭建一下环境,这里有一个链接供大家参考:http://www.yiibai.com/spring/spring-tutorial-for-beginners.html。在写这篇文章之前我看了很多视频和博客,他们首先会将一大堆理论,我看的是云里雾里,其实我感觉在学习一个东西之前没有必要对理论的东西有过多的研究,直接看例子然后自己打代码,慢慢的自己就明白了,关于ioc容器和Di注入网上有很多理论的讲解,想看的直接百度就行了,下面我直接上例子:
首先看一下我的项目结构:
创建接口OneInterface:
public interface OneInterface {
public void say(String arg);
}
创建类OneInterfaceImpl继承接口并实现接口方法:
public class OneInterfaceImpl implements OneInterface {
public void say(String arg) {
System.out.println("ServiceImpl say: " + arg);
}
}
现在如果我们想使用OneInterfaceImpl,需要这样做:
public static void main(String[] args) {
OneInterface oneInterface=new OneInterfaceImpl();
oneInterface.say("hello");
}
现在我们使用ioc容器来看看:
首先创建一个配置文件spring-ioc.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="oneInterface" class="com.mss.test.OneInterfaceImpl"></bean>
</beans>
除了一些必要的声明之外,我在里面加了OneInterfaceImpl这个类的声明,id是这个类的标识(配置文件中的id必须是唯一的),class是这个类的位置。
下面直接就可以获取OneInterfaceImpl的实例,而不需要New一个对象。
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-ioc.xml");
OneInterface oneInterface=(OneInterface) context.getBean("oneInterface");
oneInterface.say("hello");
}
这就是ioc容器,将需要的类配置到文件中,我们直接就可以获取这个类的实例。
为了以后方便测试,这里我们使用junit做一次,以后都会使用junit做测试,不懂的先去百度一下。
现在我们创建一个junit单元测试的基类:
public class UnitTestBase {
private ClassPathXmlApplicationContext context;
private String springXmlpath;
public UnitTestBase() {}
public UnitTestBase(String springXmlpath) {
this.springXmlpath = springXmlpath;
}
//测试之前执行,在这里是加载配置文件
@Before
public void before() {
if (StringUtils.isEmpty(springXmlpath)) {
springXmlpath = "classpath*:spring-*.xml";
}
try {
context = new ClassPathXmlApplicationContext(springXmlpath.split("[,\\s]+"));
context.start();
} catch (BeansException e) {
e.printStackTrace();
}
}
//测试完成之后执行
@After
public void after() {
context.destroy();
}
@SuppressWarnings("unchecked")
protected <T extends Object> T getBean(String beanId) {
try {
return (T)context.getBean(beanId);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}
protected <T extends Object> T getBean(Class<T> clazz) {
try {
return context.getBean(clazz);
} catch (BeansException e) {
e.printStackTrace();
return null;
}
}
}
接着创建一个测试类TestOneInterface:
@RunWith(BlockJUnit4ClassRunner.class)
public class TestOneInterface extends UnitTestBase{
public TestOneInterface() {
super("classpath*:spring-ioc.xml");
}
@Test
public void test() {
OneInterface oneInterface=super.getBean("oneInterface");
// OneInterface oneInterface=super.getBean(OneInterfaceImpl.class);
oneInterface.say("hello");
}
}
这样我们之间运行test这个方法就完成了和前面一样的操作。
ioc容器就先讲这么多,下面讲一下Di依赖注入。
一个类中会有一个或多个参数,我们前面通过ioc获取了类的实例,但是如果想在获取到这个实例之前就给这个类的一个或多个参数设置初始值该怎么办呢?这就用到Di依赖注入了。我们来看一个例子:
这个例子是模拟在service里处理业务逻辑,然后保存数据到DAO中。
首先是保存数据的接口和实现类:
public interface InjectionDAO {
public void save(String arg);
}
public class InjectionDAOImpl implements InjectionDAO{
public void save(String arg) {
// TODO Auto-generated method stub
System.out.println("向数据库保存数据"+arg);
}
}
然后是处理业务逻辑的接口和类:
public interface InjectionService {
public void save(String arg);
}
public class InjectionServiceImpl implements InjectionService {
InjectionDAO injectionDAO;
public void setInjectionDAO(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void save(String arg) {
// TODO Auto-generated method stub
System.out.println("处理数据"+arg);
arg=arg+":已处理";
injectionDAO.save(arg);
}
}
在InjectionServiceImpl 中有一个InjectionDAO的参数,我们就在获取InjectionServiceImpl的实例之前给InjectionDAO初始化(注意:要给参数设置set方法),修改配置文件spring-ioc.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="oneInterface" class="com.mss.test.OneInterfaceImpl"></bean>
<bean id="injectionService" class="com.mss.test.InjectionServiceImpl">
<property name="injectionDAO" ref="injectionDAO"></property>
</bean>
<bean id="injectionDAO" class="com.mss.test.InjectionDAOImpl"></bean>
</beans>
我们在配置InjectionServiceImpl时添加了一个属性:
<property name="injectionDAO" ref="injectionDAO"></property>
这里的name就是参数名,注意这里的参数名要和InjectionServiceImpl中定义的一样;ref对应的是值,也就是Id=injectionDAO的bean。这样我们在获取InjectionServiceImpl的实例时就会自动将injectionDAO的实例赋值给他。
下面我们测试一下:
@RunWith(BlockJUnit4ClassRunner.class)
public class TestOneInterface extends UnitTestBase{
public TestOneInterface() {
super("classpath*:spring-ioc.xml");
}
@Test
public void test() {
OneInterface oneInterface=super.getBean("oneInterface");
// OneInterface oneInterface=super.getBean(OneInterfaceImpl.class);
oneInterface.say("hello");
}
@Test
public void testInjection() {
InjectionService injectionService=super.getBean("injectionService");
injectionService.save("hello");
}
}
运行testInjection() 这个方法,运行结果如下:
处理数据hello
向数据库保存数据:hello:已处理
前面我们是通过set方法注入,我们也可以通过构造函数注入,修改配置文件spring-ioc.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="oneInterface" class="com.mss.test.OneInterfaceImpl"></bean>
<bean id="injectionService" class="com.mss.test.InjectionServiceImpl">
<constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
</bean>
<bean id="injectionDAO" class="com.mss.test.InjectionDAOImpl"></bean>
</beans>
这里我们把InjectionServiceImpl里的属性改为:
<constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
其实和之前是一样的,只是修改了属性名,由于是构造函数注入,我们要给类添加一个构造函数:
public class InjectionServiceImpl implements InjectionService {
InjectionDAO injectionDAO;
public InjectionServiceImpl(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void setInjectionDAO(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void save(String arg) {
// TODO Auto-generated method stub
System.out.println("处理数据"+arg);
arg=arg+":已处理";
injectionDAO.save(arg);
}
}
运行之后结果是一样的。