开启组件扫描
Spring 默认不使用注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 <context:component-scan>
元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package
属性设置)及其子包下的所有类,如果类上使用了 @Component
注解,就将该类装配到容器中。
注意:在使用 <context:component-scan>
元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 <beans>
中添加 context 相关的约束。
<?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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
最基本的扫描方式
<context:component-scan base-package="com.lin"></context:component-scan>
意味着spring会自动扫描com.lin
的包以及其子包下的所有类,如果类上使用了 @Component
注解,就将该类装配到容器中。

指定要排除的组件
<context:component-scan base-package="com.lin">
<!-- 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.lin.controller.UserController"/>-->
</context:component-scan>
仅扫描指定组件
<context:component-scan base-package="com.lin" 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.lin.controller.UserController"/>-->
</context:component-scan>
使用注解定义 Bean
注解 | 说明 |
---|---|
@Component | 该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。 |
@Repository | 该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。里面包含了@Component |
@Service | 该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。里面包含了@Component |
@Controller | 该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。里面包含了@Component |
@Autowired注入
单独使用@Autowired注解,默认根据类型装配。【默认是byType】
查看源码:
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 {
// 该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。
/// 如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。
boolean required() default true;
}
属性注入
创建UserDao接口
public interface UserDao {
public void print();
}
创建UserDaoImpl实现
@Repository // 创建Bean
public class UserDaoImpl implements UserDao {
@Override
public void print() {
System.out.println("Dao层执行结束");
}
}
创建UserService接口
public interface UserService {
public void out();
}
创建UserServiceImpl实现类
@Service// 创建Bean
public class UserServiceImpl implements UserService {
@Autowired // 自动注入,注入Bean
private UserDao userDao;
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
创建UserController类
@Controller // 创建Bean
public class UserController {
@Autowired // 自动注入,注入Bean
private UserService userService;
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
测试:
public class UserTest {
private Logger logger = LoggerFactory.getLogger(UserTest.class);
@Test
public void testAnnotation(){
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.out();
logger.info("执行成功");
}
}
set注入
修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired // 自动注入,注入Bean
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
修改UserController类
@Controller
public class UserController {
private UserService userService;
@Autowired // 自动注入,注入Bean
public void setUserService(UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
构造方法注入
修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Autowired// 自动注入,注入Bean
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
修改UserController类
@Controller
public class UserController {
private UserService userService;
// 在使用构造器注入时,如果同时有两个构造器,比如一个有参构造器,一个无参构造器
// 会优先使用这个有参的构造器,因为使用了 @Autowired
@Autowired// 自动注入,注入Bean
public UserController(UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
形参上注入
修改UserServiceImpl类
@Service
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 使用这个的前提是:这里不能有无参构造,否则会使用无参构造器
// 这样就会注入失败
public UserServiceImpl(@Autowired UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
修改UserController类
@Controller
public class UserController {
private UserService userService;
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
public void out() {
userService.out();
System.out.println("Controller层执行结束。");
}
}
一个有参构造器,无注解
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void out() {
userDao.print();
System.out.println("Service层执行结束");
}
}
当有参数的构造方法只有一个时,@Autowired注解可以省略。
@Autowired+@Qualifier:根据名称注入
接口UserDao有两个实现类
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("dao........");
}
}
@Repository
public class UserRedisDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("dao redis.........");
}
}
如果这个时候我们还根据类型注入,就会报错
@Autowired
//@Qualifier(value = "userRedisDaoImpl")
private UserDao userDao;
@Override
public void add() {
System.out.println("service.....");
userDao.add();
}
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.lin.autowired.dao.UserDao' available: expected single matching bean but found 2: userDaoImpl,userRedisDaoImpl
这个时候,就需要另外一个注解的帮忙
@Autowired
@Qualifier(value = "userRedisDaoImpl")
private UserDao userDao;
@Override
public void add() {
System.out.println("service.....");
userDao.add();
}
@Qualifier(value = "userRedisDaoImpl")
这里的value
填写类的名字。默认是类的首字母小写
@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需要引入以下依赖。】
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
源码
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Resources.class)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default Object.class;
Resource.AuthenticationType authenticationType() default Resource.AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
public static enum AuthenticationType {
CONTAINER,
APPLICATION;
private AuthenticationType() {
}
}
}
根据name注入
@Controller("myUserController")
public class UserController {
//根据名称进行注入
@Resource(name = "myUserService")
private UserService userService;
public void add() {
System.out.println("controller........");
userService.add();
}
}
@Service( "myUserService") //value 可以省略 @Service(value = "myUserService") // 起名字
public class UserServiceImpl implements UserService {
//不指定名称,根据属性名称进行注入
@Resource
private UserDao myUserDao;
@Override
public void add() {
System.out.println("service.....");
myUserDao.add();
}
}

根据属性名称注入
@Service( "myUserService") //value 可以省略 @Service(value = "myUserService") // 起名字
public class UserServiceImpl implements UserService {
//不指定名称,根据属性名称进行注入
@Resource
private UserDao myUserDao;
@Override
public void add() {
System.out.println("service.....");
myUserDao.add();
}
}
@Repository("myUserDao")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao........");
}
}

根据类型进行匹配
@Controller("myUserController")
public class UserController {
//根据类型配置
@Resource
private UserService userService;
public void add() {
System.out.println("controller........");
userService.add();
}
}
@Service( "myUserService") //value 可以省略 @Service(value = "myUserService") // 起名字
public class UserServiceImpl implements UserService {
//不指定名称,根据属性名称进行注入
@Resource
private UserDao myUserDao;
@Override
public void add() {
System.out.println("service.....");
myUserDao.add();
}
}

总结
@Resource注解:
- 默认byName注入,
- 没有指定name时把属性名当做name,
- 根据name找不到时,才会byType注入。
- byType注入时,某种类型的Bean只能有一个
Spring全注解开发
全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。
@Configuration //配置类
@ComponentScan("com.lin") //开启组件扫描
public class SpringConfig {
}
测试类
import com.lin.config.SpringConfig;
public class TestUserControllerAnno {
public static void main(String[] args) {
//加载配置类 : 其中 SpringConfig.class 就是要加载的配置类
ApplicationContext context =new AnnotationConfigApplicationContext(SpringConfig.class);
UserController controller = context.getBean(UserController.class);
controller.add();
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com