您的位置:首页 > 编程语言 > Java开发

让Spring自动扫描和管理Bean

2010-06-23 12:30 411 查看
通过在classpath自动扫描方式把组件纳入spring容器中管理
----------------------------------------------------------------------
为什么我们要使用类路径扫描的方式把组件纳入Spring容器中管理呢?前面的例子我们都是使用XML的bean定义来配置组件。尽管我们使用了依赖注入的注解减少了属性的注入配置,但是还是避免不了在配置文件中定义大量的bean,在一个稍大的项目中,通常会有上百个组件,如果这些这组件采用xml的bean定义来配置,显然会增加配置文件的体积,配置文件会很臃肿,查找及维护起来也不太方便。spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:

Xml代码



<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <context:component-scan base-package="cn.itcast"/>
</beans>

首先要引入context命名空间,接着要打开主键扫描<context:component-scan/>这个配置项
其中base-package为需要扫描的包(含子包),就是说我们要扫描哪个包下面的类,这里要注意它除了会扫描你指定包下的类,还会扫描这个包底下子包的类。
那么扫描这些类,Spring怎么知道这些类要交给Spring管理呢?这时候,我们用到了注解。spring2.5为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。

@Service用于标注业务层组件、 @Controller用于标注控制层组件(如struts中的action)、@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
这四个注解目前作用都是一样的,因为目前Spring还没对这几个注解进行特别的处理,随便标哪个注解在目前都是一样的。当然可能以后会有一些细微的变化,目前还没做到这一点。

beans.xml


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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
<context:component-scan base-package="cn.itcast"/>
</beans>

在beans.xml配置文件里,发现很干净,只是打开了配置项

PersonDaoBean.java


Java代码



package cn.itcast.dao.impl;

import org.springframework.stereotype.Repository;

import cn.itcast.dao.PersonDao;

@Repository  //这个注解告诉Spring,PersonDaoBean这个类现在要交给Spring管理,Spring扫描到
//这个类之后就知道它要把这个类纳入到Spring容器中管理
public class PersonDaoBean implements PersonDao {
public void add(){
System.out.println("执行了PersonDaoBean中的add()方法");
}
}


PersonServiceBean.java


Java代码



package cn.itcast.service.impl;

import org.springframework.stereotype.Service;

import cn.itcast.dao.PersonDao;
import cn.itcast.service.PersonService;

@Service   //当Spring扫描到这个类之后就知道它要把这个类纳入到Spring容器中管理,而且它是作为服务层组件的
public class PersonServiceBean implements PersonService {
private PersonDao personDao;

public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

public void save(){
personDao.add();
}
}

SpringTest.java


Java代码



package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.service.PersonService;

public class SpringTest {

@BeforeClass
public static void setUpBeforeClass() throws Exception {
}

@Test public void instanceSpring(){
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
PersonService personService = (PersonService)ctx.getBean("personService");
System.out.println(personService);
ctx.close();

}
}

如果输出为null,则代表没被管理。
运行单元测试代码,控制台输出:
cn.itcast.service.impl.PersonServiceBean@be0e27
cn.itcast.dao.impl.PersonDaoBean@193385d
对象已经获取到了,我们采用的是Spring自动扫描的方式把bean交给了Spring管理,采用这种方式,以后就不需要在beans.xml配置文件配置大量的bean,不需要了,这样就把开发人员从配置文件中解脱出来了,这个功能很有用哈,这也是为什么Spring2.5推出来的原因,它提供了一些更便于开发的新功能,这个注解采用扫描的方式就是他推出的一个新特点

有同学现在就可能有些想法了,默认值是bean的名称,首字母小写,那么能改么? Spring当然能提供这种修改途径
PersonServiceBean.java


Java代码



package cn.itcast.service.impl;

import org.springframework.stereotype.Service;

import cn.itcast.dao.PersonDao;
import cn.itcast.service.PersonService;

@Service("personService")
//当Spring扫描到这个类之后就知道它要把这个类纳入到Spring容器中管理,而且它是作为服务层组件的
//可以通过personService这个名称获取这个bean了
public class PersonServiceBean implements PersonService {
private PersonDao personDao;

public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

public void save(){
personDao.add();
}
}


运行单元测试代码,输出
cn.itcast.service.impl.PersonServiceBean@be0e27
cn.itcast.dao.impl.PersonDaoBean@193385d
就是说,可以通过personService这个名称得到这个bean,这里,大家就学会了怎样修改bean的名称。

这时候同学又有疑问了,bean的作用域范围有好几种啊(单例,原型prototype),目前到底是属于哪种作用域范围呢?是单例。 如果想把它改为原型prototype怎么办? 就要通过另一个注解@Scope

PersonServiceBean.java


Java代码



package cn.itcast.service.impl;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import cn.itcast.dao.PersonDao;
import cn.itcast.service.PersonService;

@Service("personService")
//当Spring扫描到这个类之后就知道它要把这个类纳入到Spring容器中管理,而且它是作为服务层组件的
//可以通过personService这个名称获取这个bean了
@Scope("prototype")  //每调用一次getBean方法,都会返回一个新的实例
public class PersonServiceBean implements PersonService {
private PersonDao personDao;

public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

public void save(){
personDao.add();
}
}

SpringTest.java


Java代码



package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.dao.impl.PersonDaoBean;
import cn.itcast.service.PersonService;

public class SpringTest {

@BeforeClass
public static void setUpBeforeClass() throws Exception {
}

@Test
public void instanceSpring() {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
PersonService personService1 = (PersonService) ctx.getBean("personService");
// 关于bean的名称,这里有条默认的规则,就是类的名称,然后第一个字母小写
PersonService personService2 = (PersonService) ctx.getBean("personService");
System.out.println(personService1 == personService2);
ctx.close();
}
}

如果打印false,则证明配置是成功的
运行单元测试代码,打印结果是false
所以通过@Scope这个注解,就可以修改bean的作用域。

这时候同学们有没有想到另一个问题? 原先我们在beans.xml里使用bean配置的时候,我们可以指定初始化init-method方法,和销毁destroy-method方法.这里怎么办呢? 我们可以使用注解的方式来指定初始化方法和销毁方法

PersonServiceBean.java


Java代码



package cn.itcast.service.impl;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.stereotype.Service;

import cn.itcast.dao.PersonDao;
import cn.itcast.service.PersonService;

@Service("personService")
//当Spring扫描到这个类之后就知道它要把这个类纳入到Spring容器中管理,而且它是作为服务层组件的
//可以通过personService这个名称获取这个bean了
public class PersonServiceBean implements PersonService {
private PersonDao personDao;

@PostConstruct   //大家注意,这个注解不是Spring的
//以后学习EJB3的时候就可以发现,这个注解也是EJB3里面用来初始化bean的注解。
//这个注解用的范围很广泛,Spring对这个注解也做了支持
//这个注解的工作呢,后面也有个处理器对它进行解析,这个处理器在哪里注册呢?
public void init(){
System.out.println("初始化");
}

@PreDestroy //在bean实例被摧毁之前,会执行这个方法
public void destory(){
System.out.println("关闭资源");
}

public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}

public void save(){
personDao.add();
}
}


beans.xml


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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
<context:component-scan base-package="cn.itcast"/>
<!--
这个配置在背后注册了很多处理器,这些处理器都会对一些注解进行解析,其中就包括我们原先采用的
<context:annotation-config></context:annotation-config>这个配置项里面的注解里面使用的处理器
就是说使用了<context:component-scan>配置的话,<context:annotation-config>配置就可以去掉
-->
</beans>


SpringTest.java


Java代码



package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.service.PersonService;

public class SpringTest {

@BeforeClass
public static void setUpBeforeClass() throws Exception {
}

@Test
public void instanceSpring() {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
PersonService personService = (PersonService) ctx.getBean("personService");
// 关于bean的名称,这里有条默认的规则,就是类的名称,然后第一个字母小写
ctx.close();
}
}

运行单元测试代码,输出
初始化
关闭资源

这里已经给大家介绍完了怎样采用扫描的方式来把组件交给Spring管理,这种方式是我们目前在新开发应用中大量使用的方式,以前的应用中这种方式是没有这种功能的,以前采用Spring2.0是没有这种功能的,这个功能是2.5推出的,这个功能一推出,确实是被很多的新开发的项目所采用,因为这种方式确实是太方便了,能够大大提高我们的开发效率
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: