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("执行成功");
}
相关推荐
草莓base5 小时前
【手写一个spring】spring源码的简单实现--bean对象的创建
java·spring·rpc
乌啼霜满天2496 小时前
Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
java·spring boot·spring·mvc
Elaine2023916 小时前
零碎04 MybatisPlus自定义模版生成代码
java·spring·mybatis
.生产的驴9 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
码蜂窝编程官方11 小时前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
AuroraI'ncoding12 小时前
时间请求参数、响应
java·后端·spring
计算机毕设指导614 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
ExiFengs15 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
瓜牛_gn16 小时前
依赖注入注解
java·后端·spring
一元咖啡17 小时前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway