【Spring注解驱动开发】如何实现方法、构造器位置的自动装配?我这样回答让面试官很满意!
在 冰河技术 微信公众号前面的文章中,我们介绍了如何使用注解来自动装配Spring组件。之前将的都是在来的字段上添加注解,那有没有什么方法可以实现方法、构造器位置的自动装配吗?今天我们就一起来探讨下如何实现方法、构造器位置的自动装配。
关注 冰河技术 技术微信公众号,后台回复“spring注解”关键字,领取项目工程源码。
再谈@Autowired注解
在我发表在 冰河技术 微信公众号的《【Spring注解驱动开发】使用@Autowired@Qualifier@Primary三大注解自动装配组件,你会了吗?》一文中简单介绍了下@Autowired注解注解的使用方法。下面,我们再来看下@Autowired注解的源码。
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 {
boolean required() default true;
}
我们通过@Autowired注解的源码可以看出,在@Autowired注解上标注有如下的注解信息。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
可以看出@Autowired注解不仅可以标注在字段上。也可以标注在构造方法上,实例方法上,参数上。
项目案例
案例准备
接下来,我们在项目中新建一个Dog类,在Doc类中有一个Cat类的引用,并且我们使用@Component注解将Dog类加载到IOC容器中,如下所示。
package io.mykit.spring.plugins.register.bean;
import org.springframework.stereotype.Component;
/**
* @author binghe
* @version 1.0.0
* @description 测试实体类
*/
@Component
public class Dog {
private Cat cat;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Dog{" + "cat=" + cat + '}';
}
}
配置好之后,我们还需要在AutowiredConfig类的@ComponentScan注解中进行配置,使其能够扫描io.mykit.spring.plugins.register.controller
包下的类,如下所示。
@Configuration
@ComponentScan(value = {
"io.mykit.spring.plugins.register.dao",
"io.mykit.spring.plugins.register.service",
"io.mykit.spring.plugins.register.controller",
"io.mykit.spring.plugins.register.bean"})
public class AutowiredConfig {
}
此时,我们可以直接在Dog类中的cat字段上添加@Autowired注解,使其自动装配。这是我们在《【Spring注解驱动开发】使用@Autowired@Qualifier@Primary三大注解自动装配组件,你会了吗?》一文中得出的结论。那今天我们就使用其他的方式来实现cat的自动装配。
标注在实例方法上
我们也可以将@Autowired注解标注在setter方法上,如下所示。
@Autowired
public void setCat(Cat cat) {
this.cat = cat;
}
当@Autowired注解标注在方法上时,Spring容器在创建对象的时候,就会调用相应的方法为对象赋值。如果标注的方法存在参数时,则方法使用的参数和自定义类型的值,需要从IOC容器中获取。
接下来,我们将AutowiredTest类的testAutowired01()方法中有关获取和打印PersonService信息的代码注释,新增获取和打印Dog信息的代码,如下所示。
@Test
public void testAutowired01(){
//创建IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
//PersonService personService = context.getBean(PersonService.class);
//System.out.println(personService);
Dog dog = context.getBean(Dog.class);
System.out.println(dog.toString());
context.close();
}
运行AutowiredTest类的testAutowired01()方法进行测试,可以看到,结果信息中输出了如下一行信息。
Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
说明已经获取到cat的信息,可以将@Autowired注解标注在方法上
为了验证最终的输出结果是否是从IOC容器中获取的,我们可以在AutowiredTest类的testAutowired01()方法中直接获取Cat的信息,如下所示。
@Test
public void testAutowired01(){
//创建IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
//PersonService personService = context.getBean(PersonService.class);
//System.out.println(personService);
Dog dog = context.getBean(Dog.class);
System.out.println(dog.toString());
Cat cat = context.getBean(Cat.class);
System.out.println(cat);
context.close();
}
我们再次运行AutowiredTest类的testAutowired01()方法进行测试,可以在输出的结果信息看到如下两行代码。
Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
io.mykit.spring.plugins.register.bean.Cat@6a400542
可以看出在Dog类中通过@Autowired注解获取到的Cat对象和直接从IOC容器中获取到Cat对象是同一个对象。
标注在构造方法上
在前面的案例中,我们在Dog类上使用了@Component注解,如下所示。
package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author binghe
* @version 1.0.0
* @description 测试实体类
*/
@Component
public class Dog {
private Cat cat;
public Cat getCat() {
return cat;
}
@Autowired
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Dog{" +
"cat=" + cat +
'}';
}
}
此时,Spring默认加载IOC容器中的组件,IOC容器启动的时候默认会调用bean的无参构造器创建对象,然后再进行初始化赋值等操作。
接下来,我们为Dog类添加一个有参构造方法,然后去除setCat()方法上的@Autowired注解,将@Autowired注解标注在有参构造方法上,并在构造方法中打印信息,如下所示。
package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author binghe
* @version 1.0.0
* @description 测试实体类
*/
@Component
public class Dog {
private Cat cat;
@Autowired
public Dog(Cat cat){
this.cat = cat;
System.out.println("调用了Dog的有参构造方法");
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Dog{" +
"cat=" + cat +
'}';
}
}
接下来,我们运行AutowiredTest类的testAutowired01()方法进行测试,可以看到输出结果信息中存在如下一行信息。
调用了Dog的有参构造方法
说明IOC容器在启动的时候调用了Dog类的有参构造方法。并且可以从输出的如下两行信息可以看出:通过Dog类的toString()方法打印出的Cat对象和直接从IOC容器中获取的Cat对象是同一个对象。
Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
io.mykit.spring.plugins.register.bean.Cat@6a400542
这里,需要大家注意的是:使用@Autowired注解标注在构造方法上时,构造方法中的参数对象也都是从IOC容器中获取的。
标注在参数上
我们也可以将@Autowired注解标注在参数上,例如,在Dog类中我们将构造方法上的@Autowired注解标注在构造方法的参数上,如下所示。
public Dog(@Autowired Cat cat){
this.cat = cat;
System.out.println("调用了Dog的有参构造方法");
}
也可以将@Autowired注解标注在setter方法的参数上,如下所示。
public void setCat(@Autowired Cat cat) {
this.cat = cat;
}
这些效果与标注在字段、实例方法和构造方法上的效果都是一样的。
例如,我们将@Autowired注解标注在构造方法的参数上,运行AutowiredTest类的testAutowired01()方法进行测试,可以看到,输出结果中,同样包含如下三行信息。
调用了Dog的有参构造方法
Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
io.mykit.spring.plugins.register.bean.Cat@6a400542
结论:无论Autowired注解标注在字段上、实例方法上、构造方法上还是参数上,都是从IOC容器中获取参数组件的值。
如果Spring的bean只有一个有参构造方法,并且这个有参构造方法只有一个参数,并且这个参数是IOC容器中的对象,当@Autowired注解标注在这个构造方法的参数上时,我们可以将@Autowired注解省略,如下所示。
public Dog(Cat cat){
this.cat = cat;
System.out.println("调用了Dog的有参构造方法");
}
接下来,我们运行AutowiredTest类的testAutowired01()方法进行测试,从输出的结果信息中,可以看出,同样输出了下面的三行信息。
调用了Dog的有参构造方法
Dog{cat=io.mykit.spring.plugins.register.bean.Cat@6a400542}
io.mykit.spring.plugins.register.bean.Cat@6a400542
说明:如果Spring的bean只有一个有参构造方法,并且这个有参构造方法只有一个参数,并且这个参数是IOC容器中的对象,当@Autowired注解标注在这个构造方法的参数上时,我们可以将@Autowired注解省略。
标注在方法位置
@Autowired注解可以标注在某个方法的位置上。这里,为了更好的演示效果,我们新建一个Fish类,在Fish类中有一个Cat类型的成员变量,如下所示。
package io.mykit.spring.plugins.register.bean;
/**
* @author binghe
* @version 1.0.0
* @description 测试类
*/
public class Fish {
private Cat cat;
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Fish{" + "cat=" + cat + '}';
}
}
接下来,我们在AutowiredConfig类中实例化Fish类,如下所示。
@Bean
public Fish fish(){
return new Fish();
}
接下来,我们在AutowiredTest类中创建testAutowired02()方法,如下所示。
@Test
public void testAutowired02(){
//创建IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
Fish fish = context.getBean(Fish.class);
System.out.println(fish);
context.close();
}
运行testAutowired02()方法,在输出的结果信息中存在如下一行信息。
Fish{cat=null}
说明此时的Fish类中的Cat对象为空。此时,我们可以将Cat对象作为一个参数传递到AutowiredConfig类的fish()方法中,并且将Cat对象设置到Fish中,如下所示。
@Bean
public Fish fish(Cat cat){
Fish fish = new Fish();
fish.setCat(cat);
return fish;
}
当然,我们也可以使用@Autowired注解来标注fish()方法中的cat参数,如下所示。
@Bean
public Fish fish(@Autowired Cat cat){
Fish fish = new Fish();
fish.setCat(cat);
return fish;
}
接下来,我们再次运行testAutowired02()方法,在输出的结果信息中存在如下一行信息。
Fish{cat=io.mykit.spring.plugins.register.bean.Cat@21de60b4}
说明Cat对象被成功创建并设置到了Fish类中。
结论:如果方法只有一个IOC容器中的对象作为参数,当@Autowired注解标注在这个方法的参数上时,我们可以将@Autowired注解省略。
重磅福利
关注「 冰河技术 」微信公众号,后台回复 “设计模式” 关键字领取《深入浅出Java 23种设计模式》PDF文档。回复“Java8”关键字领取《Java8新特性教程》PDF文档。回复“限流”关键字获取《亿级流量下的分布式限流解决方案》PDF文档,三本PDF均是由冰河原创并整理的超硬核教程,面试必备!!
好了,今天就聊到这儿吧!别忘了点个赞,给个在看和转发,让更多的人看到,一起学习,一起进步!!
写在最后
如果你觉得冰河写的还不错,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发、分布式、微服务、大数据、互联网和云原生技术,「 冰河技术 」微信公众号更新了大量技术专题,每一篇技术文章干货满满!不少读者已经通过阅读「 冰河技术 」微信公众号文章,吊打面试官,成功跳槽到大厂;也有不少读者实现了技术上的飞跃,成为公司的技术骨干!如果你也想像他们一样提升自己的能力,实现技术能力的飞跃,进大厂,升职加薪,那就关注「 冰河技术 」微信公众号吧,每天更新超硬核技术干货,让你对如何提升技术能力不再迷茫!
【Spring注解驱动开发】如何实现方法、构造器位置的自动装配?我这样回答让面试官很满意!的更多相关文章
- 【Spring注解驱动开发】如何使用@Bean注解指定初始化和销毁的方法?看这一篇就够了!!
写在前面 在[String注解驱动开发专题]中,前面的文章我们主要讲了有关于如何向Spring容器中注册bean的知识,大家可以到[String注解驱动开发专题]中系统学习.接下来,我们继续肝Spri ...
- 0、Spring 注解驱动开发
0.Spring注解驱动开发 0.1 简介 <Spring注解驱动开发>是一套帮助我们深入了解Spring原理机制的教程: 现今SpringBoot.SpringCloud技术非常火热,作 ...
- 【spring 注解驱动开发】spring自动装配
尚学堂spring 注解驱动开发学习笔记之 - 自动装配 自动装配 1.自动装配-@Autowired&@Qualifier&@Primary 2.自动装配-@Resource& ...
- 【spring 注解驱动开发】spring ioc 原理
尚学堂spring 注解驱动开发学习笔记之 - Spring容器创建 Spring容器创建 1.Spring容器创建-BeanFactory预准备 2.Spring容器创建-执行BeanFactory ...
- Spring注解驱动开发(三)-----自动装配
自动装配 概念 Spring利用依赖注入(DI),完成对IOC容器中中各个组件的依赖关系赋值. @Autowired-----自动注入 1.默认优先按照类型去容器中找对应的组件 application ...
- 【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则
写在前面 在实际项目中,我们更多的是使用Spring的包扫描功能对项目中的包进行扫描,凡是在指定的包或子包中的类上标注了@Repository.@Service.@Controller.@Compon ...
- 【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则
写在前面 Spring的强大之处不仅仅是提供了IOC容器,能够通过过滤规则指定排除和只包含哪些组件,它还能够通过自定义TypeFilter来指定过滤规则.如果Spring内置的过滤规则不能够满足我们的 ...
- 【Spring注解驱动开发】使用@Scope注解设置组件的作用域
写在前面 Spring容器中的组件默认是单例的,在Spring启动时就会实例化并初始化这些对象,将其放到Spring容器中,之后,每次获取对象时,直接从Spring容器中获取,而不再创建对象.如果每次 ...
- 【Spring注解驱动开发】使用@Lazy注解实现懒加载
写在前面 Spring在启动时,默认会将单实例bean进行实例化,并加载到Spring容器中.也就是说,单实例bean默认在Spring容器启动的时候创建对象,并将对象加载到Spring容器中.如果我 ...
随机推荐
- Springboot整合SpringSecurity--对静态文件进行权限管理
文章目录 一.要求 二.依赖管理 三.配置config文件 四.扩展 一.要求 index.html 可以被所有用户访问 1.html只能被VIP1访问 2.html只能被VIP2访问 3.html只 ...
- 使用recv函数和send函数的技巧
一些述说 recv函数用于socket通信中接收消息,接口定义如下: int recv(SOCKET s, char *buf, int len, int flags) 参数一:指定接收端套接字描述符 ...
- C++语法小记---如何判断一个变量是不是指针
如何判断一个变量是不是指针? 思路:模板函数 + 可变参数 + sizeof(函数) #include <iostream> #include <string> using n ...
- 轻松应对并发问题,Newbe.Claptrap 框架中 State 和 Event 应该如何理解?
Newbe.Claptrap 框架中 State 和 Event 应该如何理解?最近整理了一下项目的术语表.今天就谈谈什么是 Event 和 State. Newbe.Claptrap 是一个用于轻松 ...
- JAVA基础1(语法)
一.标识符和关键字 在程序中用于定义名称的都为标识符,如文件名称.类名称.方法名称或变量名称等. 在Java中标识符的定义格式由字母.数字._(下划线),$所组成,其中不能重复,不能以数字开头,不能是 ...
- Hexo博客美化之蝴蝶(butterfly)主题魔改
Hexo是轻量级的极客博客,因为它简便,轻巧,扩展性强,搭建部署方便深受广大人们的喜爱.各种琳琅满路的Hexo主题也是被各种大佬开发出来,十分钦佩,向大佬仰望,大声称赞:流批!!! 我在翻看各种主 ...
- numpy第三方库
# 导入numpy 并赋予别名 np import numpy as np # 创建数组的常用的几种方式(列表,元组,range,arange,linspace(创建的是等差数组),zeros(全为 ...
- Flask+微信公众号开发(接入指南)
目录 一.注册公众号 二.启用开发者 三.配置服务器配置 四.开发自己的需求 五.写在最后 一.注册公众号 具体的注册过程,根据官方文档一步一步来即可.这里需注意的是订阅号还是服务号:有些比较好的开发 ...
- 初学用记事本运行java报错:找不到或无法加载主类解决方法,部分出错解决办法
刚开始学习java的人第一个程序可能通过记事本运行,当中间可能会会出现各种错误,我在下面间可能解决出现的问题 1. java环境变量没有安装好 以我的win10系统为例,在装好相应的jdk后,环境变量 ...
- Python selenium 三种消息框处理和浏览器(页面跳转)句柄处理
1. alert: 警告框,只是一个提示信息,只有一个确定按钮,起提示用户的作用: 2.confirm: 确认框,确定和取消按钮会带来不同的结果.点击确定会执行操作,点击取消按钮会取消操作: 3.pr ...