一、注解配置 bean
相对于 XML 方式而言,通过注解的方式配置 bean 更加简洁和优雅,而且和 MVC 组件化开发的理念十分契合,是开发中常用的使用方式。
二、使用注解标识组件
组件:即 Spring 中管理的 bean
1)普通组件:@Component
标识一个受 Spring IOC 容器管理的组件;
2) 持久化层组件:@Repository
标识一个受 Spring IOC 容器管理的持久化层组件;
3) 业务逻辑层组件:@Service
标识一个受 Spring IOC 容器管理的业务逻辑层组件;
4) 表示层控制器组件:@Controller
标识一个受 Spring IOC 容器管理的表示层控制器组件;
使用注解将组件快速的加入到容器中需要几步:
1)给需要添加的组件上标四个注解的任何一个
2)告诉Spring自动扫描加了注解的组件;依赖context名称空间
3)一定要导入aop包,才支持加注解模式
组件命名规则:
① 默认情况下,Spring IOC 容器帮我们生成的组件,使用组件的简单类名首字母小写后得到的字符串作为组件(bean) 的 id 值。
② 可以使用组件注解的 value 属性来指定该组件(bean) id 值;
//组件的id默认为_组件类名首字母小写
@Controller("bookServletABC")或(value="bookServletABC")
public class BookServlet{}
组件的作用域—默认为单例模式
默认为单例模式,可以使用 @Scope 注解修改 bean 的作用域。
@Scope(value = "prototype")
使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的。
(1)组件的 id,默认就是组件的类名首字母小写;
(2)组件的作用域,默认就是单例的;
注意: 事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,即使将 @Respository注解用在一个表述层控制器组件上面也不会产生任何错误,所以 @Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。
三、扫描组件
使用注解标识了组件后,还需要通过 Spring 进行扫描才能侦测到。
在 Spring 的配置文件中使用 <context> 标签指定被扫描的包
context:component-scan:自动组件扫描
base-package:指定扫描的基础包,把基础包及它下面所有的包的所有了加了注解的类,自动扫描进 ioc 容器。
<context:component-scan base-package="com.spring.ioc" ></context:component-scan>
详细说明:
① base-package 属性指定一个需要扫描的基类包,Spring 容器将会扫描这个基类包及其子包中的所有类;
② 当需要扫描多个包时可以使用逗号进行分割;
③ 如果仅希望扫描特定的类而非基包下的所有类,可使用 resource-pattern 属性过滤特定的类:
示例:仅扫描 com.spring.ioc.user.service 下面的 java 类。
<context:component-scan base-package="com.spring.ioc.user" resource-pattern="service/*.class">
注意:使用扫描器的时候必须要再导入一个:spring-aop-4.0.0.RELEASE.jar 依赖。
四、使用context:include-filter指定扫描包时要包含的类—包含
<context> 中有一个 use-default-filters 属性,该属性默认为 true,表示扫描该包下的所有类。
<context:include-filter>子节点表示要包含的目标类。
注意:使用这个子节点标签,一般都是配合 use-default-filters 属性来使用,这样才能达到“仅包含某些组件”,这样的效果。即需要把 use-default-filters 属性设置为 false,不使用默认过滤器(默认扫描全部),然后只扫描的就只是 include-filter 中的规则指定的组件。
代码示例:
<--
只扫描进那些组件;默认都是全部扫描
一定要禁用掉默认的过滤规则才行:
use-default-filters属性="false"
-->
<context:component-scan base-package="com.achang" use-default-filters="false">
<!--指定只扫描那些组件-->
<context:include-filter expression="org.springframework.stereotype.Service" type="annotation"/>
</context:component-scan>
表达式:
【type="annotation"】:指定排除规则,按照注解进行包含或排除。标注指定注解的组件不要扫描
expression属性:指定注解类型的全类名
【type=assignable】:指定排除某个具体的类,按照类排除
expression属性:指定类的全类名
type=aspectj:后来aspectj表达式
type=custom:自定义一个TypeFilter;自己写代码觉得排除规则,编写一个类实现TypeFilter类的match()方法
tyoe=regex:正则表达式
过滤表达式:
类别
|
示例
|
说明
|
annotation
|
com.spring.XxxAnnotation
|
过滤所有标注了XxxAnnotation的类。这个规则根据目标组件是否标注了指定类型的注解进行过滤。
|
assignable
|
com.spring.BaseXxx
|
过滤所有BaseXxx类的子类。这个规则根据目标组件是否是指定类型的子类的方式进行过滤。
|
aspectj
|
com.spring.*Service+
|
所有类名是以Service结束的,或这样的类的子类。这个规则根据AspectJ表达式进行过滤。
|
regex
|
com\.spring\.anno\.*
|
所有com.atguigu.anno包下的类。这个规则根据正则表达式匹配到的类名进行过滤。
|
custom
|
com.spring.XxxTypeFilter
|
使用XxxTypeFilter类通过编码的方式自定义过滤规则。该类必须实现org.springframework.core.type.filter.TypeFilter接口
|
五、使用context:exclude-filter指定扫描包时不包含的类—排除
<context> 中有一个 use-default-filters 属性,该属性默认为 true,表示扫描该包下的所有类。
<context:exclude-filter>子节点表示要排除在外的目标类
注意:这个标签用法同上,不同的是,use-default-filters 的值必须为 true,表示从全部扫描的组件中排除 exclude-filter 规则中指定的组件。
<context: component-scan> 下可以拥又若干个 include-filter 和 exclude-filter 子节点,但是两者不能同时拥有
<--
扫描的时候可以排除不要的组件
-->
<context:component-scan base-package="com.achang" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
六、代码示例
DAO层:
package com.spring.ioc.User.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements IUserDao {
public UserDaoImpl() {
super();
System.out.println("UserDaoImpl构造器");
}
@Override
public void addUser() {
System.out.println("UserDaoImpl:添加成功");
}
}
Service层:
package com.spring.ioc.User.service;
import org.springframework.stereotype.Service;
import com.spring.ioc.User.dao.IUserDao;
import com.spring.ioc.User.dao.UserDaoImpl;
@Service
public class UserServiceImpl implements IUserService {
private IUserDao userDao = new UserDaoImpl();
@Override
public void addUser() {
userDao.addUser();
}
public UserServiceImpl() {
super();
System.out.println("UserServiceImpl构造器");
}
}
Controller层:
package com.spring.ioc.User.controller;
import org.springframework.stereotype.Controller;
import com.spring.ioc.User.service.IUserService;
import com.spring.ioc.User.service.UserServiceImpl;
@Controller
public class UserController {
private IUserService userService = new UserServiceImpl();
public void addUser() {
userService.addUser();
}
public UserController() {
super();
System.out.println("UserController构造器");
}
}
Spring 配置文件:
<!-- 扫描器 使用 include-filter-->
<context:component-scan base-package="com.spring.ioc.User" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!-- 扫描添加注解为 Controller 的类 -->
<context:include-filter type="assignable" expression="com.spring.ioc.User.service.IUserService"/> <!-- 扫描类型是 IUserService 的类或其子类 -->
</context:component-scan>
<!-- 扫描器 使用 exclude-filter-->
<context:component-scan base-package="com.spring.ioc.User" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="assignable" expression="com.spring.ioc.User.service.UserServiceImpl"/>
</context:component-scan>
说明:
① <context:component-scan>:扫描组件,对设置的包下面的类进行扫苗,会将加上注解的类作为spring的组件进行加载
② 作为spring的组件进行加载:会自动在spring的配置文件中生成相对应的bean,这些bean的id会以类的首字母小写为值
③ <context:include-filter>:在设定的包结构下,再次通过注解或类型具体包含到某个或某几个类
注意:在使用包含时,一定要设置use-default-filters="false",将默认的过滤(即扫描包下所有的类)关闭
④ <context:exclude-filter>:在设定的包结构下,再次通过注解或类型排除某个或某几个类
注意:在使用排除时,一定要设置use-default-filters="true",将默认的过滤(即扫描包下所有的类)打开
⑤ 切记:一个<context:component-scan>中可以出现多个include,也可以出现多个exclude,但是两个不能同时出现
org.springframework.stereotype.Controller