Spring:IOC之基于注解管理
注解只是一个标记,作用是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
在标识组件时常用的注解有:
- @Component:将类标识为普通组件
- @Controller:将类标识为控制层组件
- @Service:将类标识为业务层组件
- @Repository:将类标识为持久层组件
注意,后三个注解都由@Component注解拓展而来,对于Spring使用IOC容器管理这些组件来说没有区别,但出于代码可读性还是要严谨标记。
创建组件与扫描注解
要实现基于注解来管理bean,要先创建组件、再扫描组件,
通过注解+扫描,就可以将扫描的包下加上注解的类作为组件作为管理(其实就是在IOC容器内有了加上注解的这个类所对应的bean对象)
以下面这个例子为例 :
创建组件
创建控制层组件
1 |
|
创建接口UserService
注意 : 标记注解就是把加上注解的类在IOC容器中去配置了一个这个类型的bean,但bean的类型不能是一个接口类型,所以这个接口要加在实现上。
1 | public interface UserService { |
创建业务层组件UserServiceImpl
1 |
|
创建接口UserDao
1 | public interface UserDao { |
创建持久层组件UserDaoImpl
1 |
|
扫描组件(三种方式)
扫描组件在配置文件中进行扫描,目的在于让Spring知道哪些类加了什么注解。
使用的标签是<context:component-scan>
,扫描的包通过 base-package
字段指定。
分为三种情况 : 最基本的扫描方式、指定要排除的方式、指定要扫描的方式
最基本的扫描
1
2<context:component-scan base-package="com.atguigu">
</context:component-scan>指定要排除的组件
< context:exclude-filter >
标签:指定排除规则type
:设置排除或包含的依据type="annotation"
,根据注解排除,expression中设置要排除的注解的全类名(全类名可以在注解上右键copyreference获取)type="assignable"
,根据类型排除,expression中设置要排除的类型的全类名1
2
3
4
5
6<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/> //不扫描控制层
<!--<context:exclude-filter type="assignable"
expression="com.atguigu.controller.UserController"/>--> //不扫描UserController类
</context:component-scan>扫描指定组件
<context:include-filter >
标签:指定在原有扫描规则的基础上追加的规则use-default-filters
属性:取值false表示关闭默认扫描规则 ,此时必须设置use-default-filters=”false”,因为默认规则即扫描指定包下所有类type
:设置排除或包含的依据type="annotation"
,根据注解扫描,expression中设置要扫描的注解的全类名type="assignable"
,根据类型扫描,expression中设置要扫描的类型的全类名1
2
3
4
5
6
7<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
<!--<context:include-filter type="assignable"
expression="com.atguigu.controller.UserController"/>-->
</context:component-scan>
基于注解的bean的id
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
默认情况 :
类名首字母小写就是bean的id。例如:UserController类对应的bean的id就是userController。
自定义bean的id
可通过标识组件的注解的value属性设置自定义的bean的id
1
2
//默认为userServiceImpl public class UserServiceImpl implementsUserService {}
基于注解的自动装配
基于注解的自动装配使用 @Autowired
注解实现。只需要在成员变量上添加 @Autowired
注解即可 :
注意 : 使用了该注解之后就不需要再写setter和getter方法了。
在基于xml管理bean的环节中,自动装配的方法是在配置文件中使用autowire字段
1 |
|
@Autowired能标记的位置
其实就是在哪儿能为成员变量赋值。
- 标记在哪成员变量上,此时不需要为这个成员变量设置setter和getter方法(常用)
- 标记在set方法上
- 为当前成员变量赋值的有参构造上
@Autowired原理
默认通过
byType
方式,在IOC容器中通过匹配某个bean为属性赋值在通过
byType
方式,发现由多个类型匹配的bean时,会自动转化为byName
的方式来实现自动装配的效果。byName :将要赋值的属性的属性名作为bean的id来匹配某个bean
若
byType
和byName
都无法实现自动装配时(即IOC容器中有多个类型匹配的bean,且这些bean的id和要赋值的属性的属性名都不一样时),此时会抛出异常 :NoUniqueBeanDefinitionException (byType方式的报错)要解决第3点,可以在要赋值的属性上 ,添加
@Qualifier
来指定某个bean的id,来为这个bean属性赋值(基本不会用的)1
2
3
4
5
6
7
public class UserController {
//指定id为userServiceImpl的bean,来为当前bean赋值
private UserService userService;
...
}