注解的基础知识,请查阅 (四)【乙】Java注解
一、启用组件自动扫描
(1)使用注解管理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.xsd"> <!--开启组件扫描功能--> <!--1. 基本方式:全包扫描--> <context:component-scan base-package="com.sheeprunner.spring.c.ioc_annotation" /> </beans>
(2)关于context:component-scan的几种扫描方式
- 基本方式:全包扫描
<context:component-scan base-package="com.sheeprunner.spring.c.ioc_annotation" />
- 排除指定组件:context:exclude=filter type="annotation"/"assignable" expression="需排除包路径"
<context:component-scan base-package="com.sheeprunner.spring.c.ioc_annotation"> <!-- context:exclude-filter标签:指定排除规则 --> <!-- type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 --> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>--> </context:component-scan>
- 仅扫描指定组件:context:include=filter type="annotation"/"assignable" expression="需扫描包路径"
<context:component-scan base-package="com.atguigu" use-default-filters="false"> <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 --> <!-- use-default-filters属性:取值false表示关闭默认扫描规则 --> <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 --> <!-- type:设置排除或包含的依据 type="annotation",根据注解排除,expression中设置要排除的注解的全类名 type="assignable",根据类型排除,expression中设置要排除的类型的全类名 --> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> <!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>--> </context:component-scan>
(3)使用注解定义Bean
Spring提供了四个注解,直接标注在Java类上,用于将这些类定义为Spring Bean。
- @Component:用于Spring中的Bean,是一个泛华的概念,进表示容器中的一个组件(Bean),可用于任何层次的类上,例如Service/Dao/Controller
- @Repository:用于数据访问层(Dao层)的类,功能与@Component相同
- @Service:用于业务层(Service层)的类,功能与@Component相同
- @Controller:用于控制层(Controller层)的类,功能与@Component相同
(4)使用注解装配Bean
- @AutoWired
package org.springframework.beans.factory.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required() default true; }
- 默认根据类型装配(byType)
- 该注解可以用在构造方法、方法、参数、字段、注解类型上,甚至如果只有一个构造函数,则该注解可以省略
- required属性:默认为true,表示被注入的Bean必须存在,否则报错;如果required属性设置为false,表示注入Bean存在或不存在都没关系,存在就注入,不存在也不报错
- @Qualifier
- 如果存在多个同类型的Bean,则使用@Qualifier指定Bean的名称,例如@Qualifier("userDao")
- @Qualifier("")使用名称进行装配(byName)
- 该注解搭配@Autowired注解一起使用,也可以在Bean上使用@Primary指定优先级
当存在两个Bean,而没有用@Qualifier注解指定时,编译时抛出如下异常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookController' defined in file [D:\SheepRunner\GitProjects\springexecute\Cspring_ioc_annotation\target\classes\com\sheeprunner\spring\c\ioc_annotation\controller\BookController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bookServiceImpl': Unsatisfied dependency expressed through method 'setBookDao' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.sheeprunner.spring.c.ioc_annotation.dao.BookDao' available: expected single matching bean but found 2: bookDaoImpl,bookDaoRedisImpl
- @Resource
@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?
- @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
- @Autowired注解是Spring框架自己的。
- @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
- @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
- @Resource注解用在属性上、setter方法上。
- @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。
@Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:【如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖。】
①场景一:根据name注入
修改UserDaoImpl类
package com.atguigu.spring6.dao.impl; import com.atguigu.spring6.dao.UserDao; import org.springframework.stereotype.Repository; @Repository("myUserDao") public class UserDaoImpl implements UserDao { @Override public void print() { System.out.println("Dao层执行结束"); } }
②场景二:name未知注入
修改UserDaoImpl类
package com.atguigu.spring6.dao.impl; import com.atguigu.spring6.dao.UserDao; import org.springframework.stereotype.Repository; @Repository("myUserDao") public class UserDaoImpl implements UserDao { @Override public void print() { System.out.println("Dao层执行结束"); } }
@Resource注解:默认byName注入,没有指定name时把属性名当做name,根据name找不到时,才会byType注入。byType注入时,某种类型的Bean只能有一个
(5)全注解
全注解开发就是不再需要Spring配置文件,而是通过一个配置类来替代。
使用@Configuration
注解来标识配置类,@ComponentScan("com.sheeprunner.spring.c")
表示需要扫描的包路径。
二、原理
- 反射
详见 (四)【甲】Java反射 - 注解
详见 (四)【乙】Java注解
- 手写实现Spring IoC
基于注解和反射实现IoC容器,注册组件及装配Bean