Spring-容器:IOC-基于注解管理Bean

目录

一、基于注解管理Bean(重点)

1.1、概述

简介

​ 从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。

​ Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。

步骤

  1. 引入依赖
  2. 开启组件扫描
  3. 使用注解定义 Bean
  4. 依赖注入

使用注解

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean

1.2、开启组件扫描

概述

​ Spring 默认不支持注解装配 Bean,因此我们需要在 Spring 的 XML 配置中,通过 context:component-scan 元素开启 Spring Beans的自动扫描功能。开启此功能后,Spring 会自动从扫描指定的包(base-package 属性设置)及其子包下的所有类,如果类上使用了 @Component 注解,就将该类装配到容器中。

  • 步骤一:添加约束

    xml 复制代码
    <?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>
  • 步骤二:开启扫描方式

    xml 复制代码
    <context:component-scan base-package="com.atguigu.spring6">
    </context:component-scan>

1.2.1、指定要排除的组件

<context:exclude-filter></context:exclude-filter>标签,指定排除规则

  • type属性:设置排除或包含的依据
    • annotation,根据注解排除
    • assignable,根据类型排除
  • expression属性:设置要排除的注解或类型的全类名
xml 复制代码
<context:component-scan base-package="com.atguigu.spring6">
    <!-- 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>

1.2.2、仅扫描指定组件

  • use-default-filters="false",表示关闭默认扫描规则
  • <context:include-filter></context:include-filter>,表示指定的过滤条件来确定哪些类应该被包含在组件扫描中
xml 复制代码
<context:component-scan base-package="com.atguigu" use-default-filters="false">
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
    <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    <!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
</context:component-scan>

1.3、使用注解定义Bean

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean

1.4、使用@Autowired注入

单独使用@Autowired注解时,默认是根据类型装配

  • @Autowired注解可以标注在:构造方法上、方法上、形参上、属性上、注解上
  • @Autowired注解的required属性,
    • 属性值为True:表示注入的时候要求被注入的Bean必须是存在的,如果不存在则报错
    • 属性值为False::表示注入的时候要求被注入的Bean不一定是存在的,如果存在的话就注入,不存在的话,也不报错

1.4.1、属性注入


当使用@Autowired注解注入时,可不提供构造方法喝Setter方法,也可以注入成功

1.创建UserDao接口

java 复制代码
package com.atguigu.spring6.dao;
public interface UserDao {
    public void print();
}

2.创建UserDaoImpl实现

java 复制代码
package com.atguigu.spring6.dao.impl;
import com.atguigu.spring6.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void print() {
        System.out.println("Dao层执行结束");
    }
}

3.创建UserService接口

java 复制代码
package com.atguigu.spring6.service;
public interface UserService {
    public void out();
}

4.创建UserServiceImpl实现类

java 复制代码
package com.atguigu.spring6.service.impl;
import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
    //注入dao
    //属性注入
    @Autowired//根据类型找到对应对象,完成注入
    private UserDao userDao;

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

5.创建UserController类

java 复制代码
package com.atguigu.spring6.controller;
import com.atguigu.spring6.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
    //注入service
    //属性注入
    @Autowired//根据类型找到对应对象,完成注入
    private UserService userService;

    public void out() {
        userService.out();
        System.out.println("Controller层执行结束。");
    }
}

步骤二:演示

java 复制代码
@Test
public void testAnnotation(){
    ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
    UserController userController = context.getBean("userController", UserController.class);
    userController.out();
}

1.4.2、set注入

1.修改UserServiceImpl类

java 复制代码
@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    @Autowired//set方法注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

2.修改UserController类

java 复制代码
@Controller
public class UserController {
    private UserService userService;

    @Autowired//set方法注入
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    public void out() {
        userService.out();
        System.out.println("Controller层执行结束。");
    }
}

1.4.3、构造方法注入

1.修改UserServiceImpl类

java 复制代码
@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;
    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

2.修改UserController类

java 复制代码
@Controller
public class UserController {
    private UserService userService;
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }
    public void out() {
        userService.out();
        System.out.println("Controller层执行结束。");
    }

}

1.4.4、形参注入

1.修改UserServiceImpl类

java 复制代码
@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层执行结束");
    }
}

2.修改UserController类

java 复制代码
@Controller
public class UserController {

    private UserService userService;

    public UserController(@Autowired UserService userService) {
        this.userService = userService;
    }

    public void out() {
        userService.out();
        System.out.println("Controller层执行结束。");
    }
}

1.4.5、无注解注入

当有参数的构造方法只有一个时,@Autowired注解可以省略

1.修改UserServiceImpl类

java 复制代码
@Service
public class UserServiceImpl implements UserService {

 
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

1.4.6、联合@Qualifier注解注入

当需要注入的接口有多个实现类时,可以联合使用@Qualifier("userDaoImpl") 注解,并指定实现类的名字,即可完成属性注入

1.添加UserDaoRedisImpl类

java 复制代码
@Repository
public class UserDaoRedisImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Redis Dao层执行结束");
    }
}

说明:

  • 此时,添加实现UserDao接口类,已经造成一个接口对应两个实现类
  • 此时,程序错误,信息中说:不能装配,UserDao这个Bean的数量等于2

步骤二:修改UserServiceImpl类

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service层执行结束");
    }
}

1.5、使用@Resource注入

@Resource注解是通过名称匹配的方式来实现注入的,默认按照名称进行匹配,未指定名称,使用属性名作为name,如果找不到匹配的名称,则会尝试按照类型匹配。

用在属性上、set方法上

如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖

xml 复制代码
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

1.5.1、Name注入

1.修改UserDaoImpl类

java 复制代码
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层执行结束");
    }
}

当使用注解时,在小括号内写上属性名称表示为此Bean定义别名

2.修改UserServiceImpl类

java 复制代码
package com.atguigu.spring6.service.impl;

import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Resource(name = "myUserDao")
    private UserDao myUserDao;

    @Override
    public void out() {
        myUserDao.print();
        System.out.println("Service层执行结束");
    }
}

当使用@Resource注解时,可以使用name属性指定属性注入的别名

1.5.2、未知Name注入

1.修改UserDaoImpl类

java 复制代码
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层执行结束");
    }
}

2.修改UserServiceImpl类

java 复制代码
package com.atguigu.spring6.service.impl;

import com.atguigu.spring6.dao.UserDao;
import com.atguigu.spring6.service.UserService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao myUserDao;

    @Override
    public void out() {
        myUserDao.print();
        System.out.println("Service层执行结束");
    }
}

当使用@Resource注解时,在name属性未知的情况下,将属性注入的成员属性变量名定义为与Bean同名,即可完成注入

1.5.3、类型注入

1.原UserDaoImpl类

java 复制代码
@Repository("myUserDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao层执行结束");
    }
}

2.修改UserServiceImpl类

java 复制代码
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao userDao1;

    @Override
    public void out() {
        userDao1.print();
        System.out.println("Service层执行结束");
    }
}

当使用@Resource注解时,现在userDao1属性名不存在,但仍然可以注入成功。因为,UserDao他们的类型名相同

1.6、全注解开发

​ 全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件

使用@ComponentScan注解,进行组件扫描,从而替代了原有在xml文件中的配置

步骤一:创建配置类

java 复制代码
@Configuration
//@ComponentScan({"com.atguigu.spring6.controller", "com.atguigu.spring6.service","com.atguigu.spring6.dao"})
@ComponentScan("com.atguigu.spring6")
public class Spring6Config {
}

步骤二:演示

需要使用AnnotationConfigApplicationContext类来获取Spring6Config的字节码文件

java 复制代码
@Test
public void testAllAnnotation(){
    ApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);
    UserController userController = context.getBean("userController", UserController.class);
    userController.out();
    logger.info("执行成功");
}
相关推荐
Dorcas_FE12 分钟前
axios请求缓存与重复拦截:“相同请求未完成时,不发起新请求”
前端·spring·缓存
南部余额42 分钟前
Spring 基于注解的自动化事务
java·spring·自动化
Mr.Entropy2 小时前
请求超过Spring线程池的最大线程(处理逻辑)
数据库·sql·spring
知其然亦知其所以然3 小时前
三分钟接入!SpringAI 玩转 Perplexity 聊天模型实战
后端·spring·langchain
DKPT14 小时前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring
喂完待续16 小时前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
Volunteer Technology17 小时前
三高项目-缓存设计
java·spring·缓存·高并发·高可用·高数据量
zzywxc78721 小时前
AI在金融、医疗、教育、制造业等领域的落地案例(含代码、流程图、Prompt示例与图表)
人工智能·spring·机器学习·金融·数据挖掘·prompt·流程图
一个尚在学习的计算机小白1 天前
spring
android·java·spring
Cloud-Future1 天前
Spring MVC 处理请求的流程
java·spring·mvc