Spring更简单的读取和存储对象

之前存储 Bean 时,需要在 spring-config 中添加⼀⾏ bean 注册内容,比较麻烦
在这里插入图片描述

简介

在 Spring 中想要更简单的存储和读取对象的核心是使用注解。

  1. 使用类注解(5大类注解)
    • @Controller 控制器:验证用户请求的数据的正确性(安保系统)
    • @Service 服务:编排和调度具体的执行方法的(客服)
    • @Repository 仓库 服务持久层:和数据库交互(执行者)= DAO层(Data Access Object)数据访问层,Repository是DAO中的一种实现。
    • @Component 组件: (工具类)
    • @Configuration 配置项:存项目当中的一些配置的。
  2. 使用方法注解 @Bean

前置工作:配置扫描路径

在 spring-config.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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
    <content:component-scan base-package="com.bit.service"></content:component-scan>
</beans>

只扫描配置的com.bit.service路径下的五大类注解。

Spring设计理念:约定大于配置

类注解

@Controller 控制器

控制器:验证用户请求的数据的正确性(安保系统)

@Service 服务

服务:编排和调度具体的执行方法的(客服)

@Repository 持久层

仓库 服务持久层:和数据库交互(执行者)= DAO层(Data Access Object)数据访问层,Repository是DAO中的一种实现。

@Component

组件: (工具类)

@Configuration

配置项:存项目当中的一些配置的。

读取bean

bean命名规则

bean名称使用正常单词,默认使用原类名的首字母小写,可以读取到相应的bean
bean不正常,前两个字母都大写:使用原类名,读取相应bean
在这里插入图片描述
在这里插入图片描述

public static void main(String[] args) {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    SController sController = context.getBean("SController", SController.class);
    sController.sayHi();
}
public static void main1(String[] args) {
    
    
    //1.得到spring对象
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    //2.得到bean对象
    StudentController studentController = context.getBean("studentController", StudentController.class);
    //bean名称使用正常单词,使用原类名的首字母小写,可以读取到相应的bean
    //bean不正常,前两个字母都大写:使用原类名,读取相应bean
    //3.使用bean对象
    studentController.sayHi();
}

component-scan能否和bean标签一起使用?
可以。
bean的用法虽然麻烦,但是它可以针对component-scan做一个补充。
比如有些类确实放在component-scan 配置的类下不合适,但又需要将他存储到spring当中,这时就使用bean添加。

五大类注解可以加到不在component-scan的包中使用吗
不可以。

在component-scan下,但是没加五大类注解可以读取bean吗
不可以。一样不能将当前对象存储到spring

在component-scan下的所有子包下的类,只要加了五大类注解,同样能存储到spring中。

当在component-scan下的不同包下,类名相同。
直接的调用,在new ClassPathXmlApplicationContext这一步就会报错。
解决方案

  • 修改类名【推荐】
  • 添加value。value相当于别名:显示指定名称。
package com.java.demo.controller.bit;
import org.springframework.stereotype.Controller;

@Controller(value = "UserController2")
//value相当于别名:显示指定名称。
public class UserController {
    
    
    public void sayHi() {
    
    
        System.out.println("do com java demo controller bit - User Controller sayHi");
    }
}
package com.java.demo;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    
    
    public void sayHi() {
    
    
        System.out.println("do com java demo User Controller sayHi");
    }
}
public static void main(String[] args) {
    
    
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
    UserController userController = context.getBean("userController", UserController.class);
    userController.sayHi();

    //UserController2 是注解中value的值
    com.java.demo.controller.bit.UserController userController2 = context.getBean("UserController2", com.java.demo.controller.bit.UserController.class);
    userController2.sayHi();
}

五大类注解的关系

@Controller / @Service / @Repository / @Configuration 都是@Component的子类,都是针对于@Component的扩展。

为什么需要五大类注解

Java 标准分层(至少3层):

  1. 控制层
  2. 服务层
  3. 数据持久层
    在这里插入图片描述
    五大类注解就是根据分层的需求进行创建的。
    需要五大注解的原因:让程序员看到注解之后知道当前类的作用。

阿里巴巴标准分层:
在这里插入图片描述

方法注解Bean

使用Bean注解时,要求当前的方法必须有返回值,因为bean注解是将当前方法的返回值存到spring当中的。
Bean注解在使用的时候,要配合五大类注解,才能将方法返回的对象存到spring当中。【为spring性能设计所规定的策略】

Bean的命名规则:默认,@Bean存储的对象的名称 = 方法名
@Bean(name = "u1") / @Bean(value = "u1") 对bean进行重命名,可以有多个别名,数组表示。@Bean(name = {"user1", "u1"})

@Component
public class UserBeans {
    
    
    @Bean(name = "u1")
    public User user1() {
    
    
        User user = new User();
        user.setUid(1);
        user.setUsername("ss");
        user.setPassword("123");
        user.setAge(12);
        return user;
    }
}
@Component
public class UserBeans {
    
    
    @Bean(name = {
    
    "user1", "u1"})
    public User user1() {
    
    
        User user = new User();
        user.setUid(1);
        user.setUsername("ss");
        user.setPassword("123");
        user.setAge(12);
        return user;
    }
}

Q:当bean注解使用了重命名后,默认的方法名,是否还可以继续获取该对象呢?
A:不行。

spring容器中允许

阿里巴巴Java开发手册
分层领域模型规约:
• DO(Data Object):此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
• DTO(Data Transfer Object):数据传输对象,Service 或 Manager 向外传输的对象。
• BO(Business Object):业务对象,可以由 Service 层输出的封装业务逻辑的对象。
• Query:数据查询对象,各层接收上层的查询请求。注意超过 2 个参数的查询封装,禁止使用 Map 类
来传输。
• VO(View Object):显示层对象,通常是 Web 向模板渲染引擎层传输的对象。
/
实体类的命名规则:
基本对象(和数据库中的一张表):表名:Userinfo 代码名:Userinfo / UserinfoEntity / UserinfoDO
扩展对象:UserinfoVO / UserinfoOtherVO / Userinfo…VO / …

总结:将对象存储到spring容器:

  1. 在spring配置文件中 <bean id="" class="com.java."></bean>
  2. 通过注解存储bean
    1. 配置了扫描路径,只有扫描路径下的包才有可能将bean存储到spring
    2. 加了五大类注解或@Bean方法注解

获取Bean对象(对象装配)

获取 bean 对象也叫做对象装配,是把对象取出来放到某个类中,有时候也叫对象注⼊。
对象装配(对象注入):更加简单的读取bean(从spring容器中读取某个对象,放到当前类里)
对象装配(对象注入)的实现方法以下 3 种:

  1. 属性注入
  2. Setter 注入
  3. 构造方法注入

属性注入

属性注⼊使⽤ @Autowired 实现

@Controller
public class UserController {
    
    

    @Autowired  //注入对象(更加简单的从spring当中读取对象)
    private UserService userService;

    public void sayHi() {
    
    
        System.out.println("do com java demo User Controller sayHi");
        userService.sayHi();
    }
}

优点:简单
缺点:

  1. 无法实现final修饰的变量注入
    在这里插入图片描述

  2. 兼容性不好,只适用于IoC容器

  3. 风险:因为写法简单,所以违背 单一设计原则 的概率更大。

Setter注入

@Controller
public class UserController {
    
    
    //setter注入
    private UserService userService;

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

    public void sayHi() {
    
    
        System.out.println("do com java demo User Controller sayHi");
        userService.sayHi();
    }
}

优点:符合单一设计原则,每次都只传递一个对象
缺点:

  1. 不能注入不可变对象(finally对象)
  2. 使用setter注入的对象可能会被修改。set方法可以在任意的地方调用设置。

构造方法注入【官方推荐】

@Controller
public class UserController {
    
    
    //构造方法注入
    private UserService userService;

    @Autowired   //可以不写
    public UserController(UserService userService) {
    
    
        this.userService = userService;
    }

    public void sayHi() {
    
    
        System.out.println("do com java demo User Controller sayHi");
        userService.sayHi();
    }
}

特点:如果当前类中只有一个构造方法的话,那么@Autowired注解可以省略
优点:

  1. 可以注入一个不可变的对象(使用finally修饰的对象)
  2. 注入的对象不会被改变(构造方法只能执行一次)
  3. 构造方法注入,可以保证注入对象完全被初始化
  4. 通用性更好
    缺点:

为什么构造方法可以注入一个不可变的对象,而属性注入和setter注入不行?
在Java的规定中,被finally修饰的对象,必须满足两个条件中的任意一个
1.finally修饰的对象,要么在创建的时候直接赋值
2.finally修饰的对象,要么在构造方法中赋值

@Resource:另一种注入关键字

@Autowired 和 @Resource 的区别

  • 出身不同:@Autowired 来自于 Spring,而 @Resource 来自于 JDK 的注解;
  • 使用时设置的参数不同:相比于 @Autowired 来说,@Resource 支持更多的参数设置,例如
    name 设置,根据名称获取 Bean。
  • @Autowired 可用于 Setter 注入、构造函数注入和属性注入,而 @Resource 只能用于 Setter 注
    入和属性注入,不能用于构造函数注入。
  • 查找bean的方式不同。在spring容器中查找bean有两种方式 1. 根据类型查找;2. 根据名称查找。
    • @Autowired:先根据类型查找(byType),再根据名称查找(byName)
    • @Resource:先根据名称去查,再根据类型去查
@Controller
public class UserController2 {
    
    
// @Autowired,在拿值的时候,名字必须和bean里面一样
    @Autowired
    private User user1;
    
    public void sayHi() {
    
    
        System.out.println("do com java demo Controller UserController2 sayHi");
        System.out.println(user1.getUsername());
    }
}
@Controller
public class UserController2 {
    
    

    @Resource(name = "user1")  // 在容器里面拿值的时候,找名叫user1的bean,
    private User user;
    
    public void sayHi() {
    
    
        System.out.println("do com java demo Controller UserController2 sayHi");
        System.out.println(user.getUsername());
    }
}
@Controller
public class UserController2 {
    
    
    //使用 @Qualifier + @Qualifier(value = "user1") 实现和@Resource(name = "user1")一样的功能
    @Autowired
    @Qualifier(value = "user1")
    private User user;

    public void sayHi() {
    
    
        System.out.println("do com java demo Controller UserController2 sayHi");
        System.out.println(user.getUsername());
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44431128/article/details/130074325