配置 bean有两种方式:基于 XML 文件的方式;基于注解的方式(基于注解配置 Bean;基于注解来装配 Bean 的属性)
之前我们都是在IOC配置文件xml中配置bean,现在我们尝试在代码源文件中通过注解的方式标注特定类对应的Bean。
在 classpath 中扫描组件
组件扫描(component scanning): Spring 能够从 classpath 下自动扫描, 侦测和实例化具有特定注解的组件.
特定组件包括:
@Component: 基本注解, 标识了一个受 Spring 管理的组件
@Respository: 标识持久层组件
@Service : 标识服务层(业务层)组件
@Controller : 标识表现层组件
对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写. 也可以在注解中通过 value 属性值标识组件的名称
当在组件类上使用了特定的注解之后, 还需要在 Spring 的配置文件中声明 <context:component-scan> :
base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包里及其子包中的所有类.
当需要扫描多个包时, 可以使用逗号分隔.
如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类,示例:
<context:include-filter> 子节点表示要包含的目标类
<context:exclude-filter> 子节点表示要排除在外的目标类
<context:component-scan> 下可以拥有若干个 <context:include-filter> 和 <context:exclude-filter> 子节点
<context:include-filter> 和 <context:exclude-filter> 子节点支持多种类型的过滤表达式:
好,我还是用例子来说说:
首先,我们定义一组类,分别是表示层的控制器、持久层的访问器、业务层的调用器、模型层的数据bean。
package com.happyBKs.annotations.beans; import org.springframework.stereotype.Component; @Component public class PositionBean { }
package com.happyBKs.annotations.controllers; import org.springframework.stereotype.Controller; @Controller public class PositionController { public void execute() { System.out.println("PositionController execute..."); } }
package com.happyBKs.annotations.respository; public interface PositionRespository { void save(); }
package com.happyBKs.annotations.respository; import org.springframework.stereotype.Repository; @Repository("positionRespository") public class PositionRespositoryImpl implements PositionRespository { public void save() { // TODO Auto-generated method stub System.out.println("PositionRespository save..."); } }
package com.happyBKs.annotations.services; import org.springframework.stereotype.Service; @Service public class PositionService { public void save() { System.out.println("PositionService save..."); } }
注意到没?我们为不同的bean注解了不同的注解,分别对应不同的层次。但是其实我们可以使用@Respository注解Service层的bean,@Component注解表示层的bean,都是没问题的。这里注解标识的不同制式出于规范的需要。
IOC配置文件这时候不需要在配置bean了,但是还是需要为spring自动扫描源码包寻找注解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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 指定Spring IOC容器扫描的包 --> <context:component-scan base-package="com.happyBKs.annotations"></context:component-scan> </beans>
这里有个IDE的小细节,之前我们可以看到我们定义的那些类的源文件的LOGO就是一般的Java源文件LOGO。但是配置文件写好之后,发现源文件上出现了S。
测试代码:
package com.happBKs.spring.iocaop; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.happyBKs.annotations.beans.PositionBean; import com.happyBKs.annotations.controllers.PositionController; import com.happyBKs.annotations.respository.PositionRespository; import com.happyBKs.annotations.services.PositionService; public class TestAnnotation { @Test public void test1() { ApplicationContext ac=new ClassPathXmlApplicationContext("beans-annotation.xml"); PositionBean pb=(PositionBean)ac.getBean("positionBean"); System.out.println(pb); PositionController pc=(PositionController)ac.getBean("positionController"); System.out.println(pc); PositionRespository pr=(PositionRespository)ac.getBean("positionRespository"); System.out.println(pr); PositionService ps=(PositionService)ac.getBean("positionService"); System.out.println(ps); } }
输出:
com.happyBKs.annotations.beans.PositionBean@10e3c6a3
com.happyBKs.annotations.controllers.PositionController@5a05fffe
com.happyBKs.annotations.respository.PositionRespositoryImpl@3fe9aade
com.happyBKs.annotations.services.PositionService@5d0f59a
当然我们也可以通过前面介绍的方,过滤或者追加相关的包或类。
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- 指定Spring IOC容器扫描的包 --> <!-- <context:component-scan base-package="com.happyBKs.annotations"></context:component-scan> --> <!-- 指定Spring IOC容器扫描的包 --> <!-- <context:component-scan base-package="com.happyBKs.annotations" resource-pattern="beans/*.class"></context:component-scan> --> <!-- 指定Spring IOC容器扫描的包 --> <!-- <context:component-scan base-package="com.happyBKs.annotations"> <context:exclude-filter type="assignable" expression="com.happyBKs.annotations.controllers.PositionController" /> </context:component-scan> --> <context:component-scan base-package="com.happyBKs.annotations"> <context:exclude-filter type="annotation" expression="com.happyBKs.annotations.respository.PositionRespositoryImpl" /> </context:component-scan> </beans>
当相关类被排除了,那么相应的bean就没有了,测试程序会报错。
这里需要特别注意的是,注解方式构造bean,默认的bean的Id名字是类名的首字母小写后的字符串。但是如果在注解时指明了注解名称的除外。