spring用注解读取与获取对象

前言

上一篇博客简单的介绍了spring的功能与使用,可以看到我们创建一个对象,就需要在xml中存储一个bean对象,这种操作非常的繁琐,因此spring发明了使用注解来快捷存储bean对象

配置工作

我们在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="">
    </content:component-scan>

</beans>

其中base-package=""中填写要存储的包路径,比如我们的对象存储在com.demo.controller路径下,那么就填写

<content:component-scan base-package="com.demo.component">
    </content:component-scan>

在这里插入图片描述

存储Bean对象

有多种注解可以存储对象

  1. 类注解:@Controller @Service @Repository @Component @Configuration
  2. @Bean

@Controller

在类上使用@Controller 注解,就可以存储bean对象

package com.demo.component;

import org.springframework.stereotype.Controller;

@Controller
public class ArticleController {
    public String sayHi(){
        return "hi";
    }
}

获取使用bean对象和之前的方法一样,使用ApplicationContext

spring规定,使用类名的小驼峰作为id,因此我们可以通过下面这种格式获取bean对象

ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ArticleController articleController = context.getBean("articleController", ArticleController.class);
        System.out.println(articleController.sayHi());

如果我们的类名本身首字母就是小写的,那么获取Bean的名称和类名一样,如果我们的类名第一个字母和第二个字母都是大写字母,比如说AApple,那么Spring规定,也是使用原类名来获取Bean对象

如果我们的类直接创建于java包下,而不是自定义的包下,我们想要将这个类注入到Spring中,那么要按照下面这个方法来操作

将扫描目录改为通配符**,使用通配符,可以扫描所有的这个项目下所有的类文件

<content:component-scan base-package="**">
    </content:component-scan>

并且,我们在main方法调用时,必须使用BeanFactory来获取上下文

BeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
User user = (User) factory.getBean("user");
System.out.println(user.sayHi());

但是可以发现,使用这个方法,执行的速度是非常慢的,因此非常不建议大家这样编写

其他类注解

使用其他四个类注解,也可以实现和@Controller相同的功能,其基本原理和实现方式和Controller是一样的,事实上,@Component是其他四个类注解的父类

package com.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class StudentService {
    public void sayHi(){
        System.out.println("service : hi");
    }
}

在我们的Spring core中,这些类注解的用途都是一样的,只有后面的Spring MVC和SpringBoot中,这些类注解才有他们不同的功能

分成五个不同类注解的原因:

  1. 我们可以通过类注解来判断这个类是用来干嘛的
  2. 五个类在SpringMVC和SpringBoot中有不同的功能

下面来简单介绍一下这五大类注解的用途:
当我们用户在前端访问网站时,@Controller对应的类负责接待这些用户,确认用户的参数是否合理,相当于我们进餐厅后的接待员,会把你领到位置上

接着,数据传给@Service对应的类,负责判断前端的请求需要调用什么功能,相当于餐厅的服务员,会把你想要的菜告诉后厨

然后,数据传给@Repository对应的类,其于数据库直接相连,会操作数据库的增删改查,相当于餐厅中的厨师,会把饭给你做好拿出来

而@Configuration对应的类,用来配置项目的一些信息

@Component对应的类,则提供一些项目中的公共方法,例如我们项目中确认用户是否登陆,整个项目都需要这个方法

下面来简单翻译一下这些词的含义

  1. @Component 组件,归属于公共工具类
  2. @Controller 控制器, 归属于业务逻辑层
  3. @Service 服务,归属于服务层
  4. @Repository 仓库,归属于持久层
  5. @Configuration 配置,归属于配置层

@Bean

除了在类上使用五大类注解,可以在Spring中存储这个类,我们还可以在方法上使用@Bean这个注解,可以将方法的返回对象存储在Spring中

需要注意的是,为了防止需要扫描大量的方法,因此@Bean在方法上注解了后,还需要在这个方法对应的类上使用五大类注解

代码实例:
我们在别的包实现student类

package com.demo.model;


public class Student {
    private int age;
    private int id;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", id=" + id +
                '}';
    }
}

然后在一个返回Student的方法上注解@Bean,在整个类上注解五大类注解

package com.demo.component;

import com.demo.model.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class StudentBean {
    @Bean
    public Student student(){
        Student student = new Student();
        student.setId(1);
        student.setAge(1);
        return student;
    }
}

就可以使用上下文对象来获取Student对象了

Student student = context.getBean("student",Student.class);
System.out.println(student);

其id和五大类注解一样,默认是类名的小驼峰,由于方法可能有很多重名的,因此我们可以在@Bean后设置name属性,还可以设置多个

@Bean(name = {"stu","学生","s"})

在设置name属性后,原先的小驼峰就找不到对应的类了

获取对象

属性注入

按照前面讲的,我们需要将@Service的类注入到@Controller类中,那么我们就可以使用属性注入

先实现一个StudentService类

package com.demo.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class StudentService {
    public void sayHi(){
        System.out.println("service : hi");
    }
}

在StudentController类中,就可以自动的获取studentService对象

package com.demo.controller;

import com.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class StudentController {
    @Autowired
    private StudentService studentService;
    
    public void sayHi(){
        studentService.sayHi();
    }
}

可以看出,这种方法十分简单快捷

但是,具有如下的缺点:

  • 不能修饰final对象
  • 只适用于IoC容器
  • 容易违背单一设计原则(一个方法干一件事)
    在这里插入图片描述

set注入

在set方法上使用@Autowired注解可以得到studentService对象

private StudentService studentService;

@Autowired
public void setStudentService(StudentService studentService) {
    this.studentService = studentService;
}
  • 这种方法相比较于属性注入来说更符合单一设计原则
  • 和属性注入一样,set注入不能用于final对象

构造方法注入

在构造方法上使用@Autowired注解可以得到studentService对象

private StudentService studentService;

@Autowired
public StudentController(StudentService studentService) {
    this.studentService = studentService;
}
  • 这种方法可以注入final对象
  • 由于构造方法是在类加载时执行一次,因此不会象set注入一样,可能造成多次修改
  • 注入的对象会初始化
  • 是spring最推荐使用的主流方法

@Resource

除了@Autowired以外,还有@Resource可以使用,其使用方法和@Autowired基本一致,有以下几种不同

  • @Autowired来自Spring @Resource来自JDK
  • @Resource支持更多的参数设置
  • @Resource只支持属性注入和set注入,不支持构造函数注入

当我们一个类中有多个Bean对象,返回同一个对象的类型,而另一个类中只适用对象名称来接收,就会出现报错

StudentBean类:

package com.demo.component;

import com.demo.model.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class StudentBean {
//    @Bean(name = {"stu","学生","s"})
    @Bean
    public Student student1(){
        Student student = new Student();
        student.setId(1);
        student.setAge(1);
        return student;
    }

    @Bean
    public Student student2(){
        Student student = new Student();
        student.setId(2);
        student.setAge(2);
        return student;
    }
}

StudentController类

package com.demo.controller;

import com.demo.model.Student;
import com.demo.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class StudentController {
	@Autowired
    private Student student;

    public void sayHi(){
        System.out.println(student.toString());
    }
}

直接运行的话就会报错
在这里插入图片描述
我们可以使用@Qualifier注解来定义名称

@Autowired
@Qualifier(value = "student2")
private Student student;

public void sayHi(){
    System.out.println(student.toString());
}

或者,也可以直接使用@Resource的属性来指定名称

@Resource(name = "student2")
private Student student;

public void sayHi(){
    System.out.println(student.toString());
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值