I. 基于注解方式配置 Bean
在之前的教程中, 配置 Bean 的方式都是通过 xml 配置文件中声明 bean 的定义来配置的,那么还有一种方式是通过 java 的注解(annatation
) 的方式来进行 bean 的配置和装配 bean 的属性的, 下面我们来讲一下如和通过注解的方式来配置 bean
II. 组件扫描
组件扫描(component scanning)
: Spring 能够从 classpath 中进行自动扫描,侦测并实例化具有特定注解的组件。
这些特定组件包括:
@Component
: 基本注解,标识了一个受 Spring 管理的组件@Repository
: 标识持久层组件@Service
: 标识服务层(业务层) 组件@Controller
: 标识表现层组件
对于扫描到的组件, Spring 中有默认的命名策略
,即使用非限定类名
,第一个字母小写; 也可以在注解中通过 value
属性来标识组件的名称。举个例子,比如一个类类名叫 CarFactory
, 那么默认的命名策略,这个组件就叫做 carFactory
,如果通过 value 来指定它叫 audiFactoryImpl,
那么这个组件就叫做 audiFactoryImpl
如果只在class中标识了注解,这时候 IOC 容器还不能去管理这个组件,还需要进行配置:
- 当组件类上使用了特定的注解之后,还需要在Spring 的配置文件中声明
<context:component-scan>
base-package
属性指定一个需要扫描的基类包, Spring 容器将会扫描这个基类包里及其子包中的所有类
- 如果需要扫描多个包的时候,可以使用
,
进行分隔 - 如果仅希望扫描特定的类而非基类包下所有的类,那么可以使用
resource-pattern
属性来过滤特定的类,比如:
<context:component-scan
base-package="org.lovian.spring.beans"
resource-pattern="autowire/*.class"
/>
<context:include-filter>
子节点表示要包含的目标类<context:exclude-filter>
子节点标识要排除在外的目标类<context:component-scan>
下可以拥有若干个<context:include-filter>
和<context:exclude-filter>
子节点<context:include-filter>
和<context:exclude-filter>
子节点支持多种类型的表达式- type:
annotation
- expression:
org.lovian.XxxAnnotation
- 所有标注了 XxxAnnotation 的类,该类型采用目标类是否标注了某个注解进行过滤
- expression:
- type:
assinable
- expression:
org.lovian.XxxService
- 所有继承或者扩展 XxxService 的类,该类型采用目标类是否继承或者扩展某个特定类进行过滤
- expression:
- type:
aspectj
- expression:
org.lovian..*Service+
- 所有类名以 Service 结束的类及继承或扩展它们的类,该类型采用 AspectJ 表达式进行过滤
- expression:
- type:
regex
- expression:
org.\lovian\.anno\..*
- 所有 org.lovian.anno 包下的类,该类型采用正则表达式根据类的类名进行过滤
- expression:
- type:
custom
- expression:
org.lovian.XxxTypeFilter
- 采用 XxxTypeFilter通过代码的方式定义过滤规则,该类必须实现
org.springframework.core.type.TypeFilter
接口
- expression:
- type:
III. Annotation 代码示例
我们使用 annotation 来简单模拟一些三个层次的一个Spring 简单应用,同时拥有 repository 层, service 层和 controller 层
repository 层:
package org.lovian.spring.bean.annotation.repository;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
public interface UserRepository {
void save();
}
实现UserRepository接口,并指定 annotation 的 value属性
package org.lovian.spring.bean.annotation.repository;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
@Repository(value = "userRepository")
public class UserRepositoryImpl implements UserRepository {
public void save() {
System.out.println("User Repository saved.");
}
}
service 层:
package org.lovian.spring.bean.annotation.service;
import org.springframework.stereotype.Service;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
@Service
public class UserService {
public void add(){
System.out.println("UserService add...");
}
}
controller 层:
package org.lovian.spring.bean.annotation.controller;
import org.springframework.stereotype.Controller;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
@Controller
public class UserController {
public void execute(){
System.out.println("UserController execute...");
}
}
然后定义一个 model,指定 @Component
package org.lovian.spring.bean.annotation;
import org.springframework.stereotype.Component;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
@Component
public class TestObject {
}
然后需要配置一个 Spring 的配置文件 annotation_bean.xml,引入 context namespace
, 指定 IOC 容器扫描的包
<?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.xsd">
<context:component-scan base-package="org.lovian.spring.bean.annotation"/>
</beans>
然后我们就可以从 IOC 东西中获取刚才用 annotation 标注的类的 bean 实例:
package org.lovian.spring.demo;
import org.lovian.spring.bean.annotation.TestObject;
import org.lovian.spring.bean.annotation.controller.UserController;
import org.lovian.spring.bean.annotation.repository.UserRepository;
import org.lovian.spring.bean.annotation.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Author: PENG Zhengshuai
* Date: 4/19/18
* lovian.org
*/
public class AnnotationDemo {
public static void main(String[] args) {
ApplicationContext actx = new ClassPathXmlApplicationContext("config/annotation-beans.xml");
TestObject testObject = (TestObject) actx.getBean("testObject");
System.out.println(testObject);
UserRepository userRepository = (UserRepository) actx.getBean("userRepository");
System.out.println(userRepository);
userRepository.save();
UserService userService = (UserService) actx.getBean("userService");
System.out.println(userService);
userService.add();
UserController userController = (UserController) actx.getBean("userController");
System.out.println(userController);
userController.execute();
}
}
得到结果如下:
org.lovian.spring.bean.annotation.TestObject@5e955596
org.lovian.spring.bean.annotation.repository.UserRepositoryImpl@50de0926
User Repository saved.
org.lovian.spring.bean.annotation.service.UserService@2473b9ce
UserService add...
org.lovian.spring.bean.annotation.controller.UserController@60438a68
UserController execute...
可以看出,通过注解的方式,和通过xml配置bean的方式一样,都可以从 IOC 容器中拿到 bean。
接下来要通过 context:component-scan
中的属性标签来进行 bean 扫描的过滤:
- 通过
resource-pattern
扫描指定包下的类:
<!-- 只扫描 org.lovian.spring.bean.annotation.repository 包下的 class 文件-->
<context:component-scan
base-package="org.lovian.spring.bean.annotation"
resource-pattern="repository/*.class"
/>
- 通过
context:include-filter
来指定包含的类
<!-- 指定一定要包含(not only)标注了 @Repository 的类-->
<context:component-scan base-package="org.lovian.spring.bean.annotation">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!-- 指定只包含(only)标注了 @Repository 的类,需要设置 use-default-filters属性为 false,意思是说,只用我们定义的 filter,而不用默认的filter-->
<context:component-scan
base-package="org.lovian.spring.bean.annotation"
use-default-filters="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
- 通过
context:exclude-filter
来指定不包含的类
<!-- 指定不包含标注了org.springframework.stereotype.Repository 的 bean, 即不包含标注了@Repository的所有类-->
<context:component-scan base-package="org.lovian.spring.bean.annotation">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
Share this on