37岁程序员被裁,Spring系列:自动注入

                 '}';
    }
}

public static class Service2 { //@1
    private String desc;

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return "Service2{" +
                "desc='" + desc + '\'' +
                '}';
    }
}

private Service1 service1;//@3
private Service2 service2;//@4

public Service1 getService1() {
    return service1;
}

public void setService1(Service1 service1) {
    System.out.println("setService1->" + service1);
    this.service1 = service1;
}

public Service2 getService2() {
    return service2;
}

public void setService2(Service2 service2) {
    System.out.println("setService2->" + service2);
    this.service2 = service2;
}

@Override
public String toString() {
    return "DiAutowireByName{" +
            "service1=" + service1 +
            ", service2=" + service2 +
            '}';
}

}


这个类中有2个属性,名称为:

*   service1

*   service2

这两个属性都有对应的set方法。

下面我们在bean xml中定义2个和这2个属性同名的bean,然后使用按照名称进行自动注入。

diAutowireByName.xml

<?xml version="1.0" encoding="UTF-8"?>

<bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
    <property name="desc" value="service1"/>
</bean>
<bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
    <property name="desc" value="service2"/>
</bean>
<bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
    <property name="desc" value="service2-1"/>
</bean>

<!-- autowire:byName 配置按照name进行自动注入 -->
<bean id="diAutowireByName1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName"/>

<!-- 当配置了自动注入,还可以使用手动的方式自动注入进行覆盖,手动的优先级更高一些 -->
<bean id="diAutowireByName2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName">
    <property name="service2" ref="service2-1"/>
</bean>

上面注释认真看一下。

@1:定义了一个名称为service1的bean

@2:定义了一个名称为service2的bean

@3:定义diAutowireByName需要将autowire的值置为byName,表示按名称进行自动注入。

spring容器创建diAutowireByName对应的bean时,会遍历DiAutowireByName类中的所有set方法,然后得到set对应的属性名称列表:{“service1”,“service2”},然后遍历这属性列表,在容器中查找和属性同名的bean对象,然后调用属性对应的set方法,将bean对象注入进去

测试用例

package com.javacode2018.lesson001.demo6;

import com.javacode2018.lesson001.demo5.IocUtils;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class DiAutowireTest {

/**
 * 按照名称进行注入
 */
@Test
public void diAutowireByName() {
    String beanXml = "classpath:/com/javacode2018/lesson001/demo6/diAutowireByName.xml";
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println(context.getBean("diAutowireByName"));
}

}


效果

运行diAutowireByName输出:

setService1->Service1{desc=‘service1’}
setService2->Service2{desc=‘service2’}
setService2->Service2{desc=‘service2-1’}
setService1->Service1{desc=‘service1’}
DiAutowireByName{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2’}}
DiAutowireByName{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2-1’}}


## 优缺点

按名称进行注入的时候,要求名称和set属性的名称必须同名,相对于硬编码的方式注入,确实节省了不少代码。

# 按照类型进行自动注入

## 用法

autowire设置为byType


spring容器会遍历x类中所有的set方法,会在容器中查找和set参数类型相同的bean对象,将其通过set方法进行注入,未找到对应类型的bean对象则set方法不进行注入。

需要注入的set属性的类型和被注入的bean的类型需要满足isAssignableFrom关系。

按照类型自动装配的时候,如果按照类型找到了多个符合条件的bean,系统会报错。

set方法的参数如果是下面的类型或者下面类型的数组的时候,这个set方法会被跳过注入:

Object,Boolean,boolean,Byte,byte,Character,char,Double,double,Float,float,Integer,int,Long,Short,shot,Enum,CharSequence,Number,Date,java.time.temporal.Temporal,java.net.URI,java.net.URI,java.util.Locale,java.lang.Class

来看看案例吧。

## 案例

DiByType.java

package com.javacode2018.lesson001.demo6;

/**

  • 按照类型自动注入
    */
    public class DiAutowireByType {
    public static class Service1 {
    private String desc;

     public String getDesc() {
         return desc;
     }
    
     public void setDesc(String desc) {
         this.desc = desc;
     }
    
     @Override
     public String toString() {
         return "Service1{" +
                 "desc='" + desc + '\'' +
                 '}';
     }
    

    }

    public static class Service2 {
    private String desc;

     public String getDesc() {
         return desc;
     }
    
     public void setDesc(String desc) {
         this.desc = desc;
     }
    
     @Override
     public String toString() {
         return "Service2{" +
                 "desc='" + desc + '\'' +
                 '}';
     }
    

    }

    private Service1 service1;
    private Service2 service2;

    public Service1 getService1() {
    return service1;
    }

    public void setService1(Service1 service1) {
    System.out.println(“setService1->” + service1); //@1
    this.service1 = service1;
    }

    public Service2 getService2() {
    return service2;
    }

    public void setService2(Service2 service2) {
    System.out.println(“setService2->” + service2); //@2
    this.service2 = service2;
    }

    @Override
    public String toString() {
    return “DiByType{” +
    “service1=” + service1 +
    “, service2=” + service2 +
    ‘}’;
    }
    }


DiAutowireByType类中有2个set方法分别来注入Service1和Service2,两个set方法中都输出了一行文字,一会执行的时候可以通过这个输出可以看出set方法是否被调用了。

diAutowireByName.xml

<?xml version="1.0" encoding="UTF-8"?>

<bean id="service1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service1">
    <property name="desc" value="service1"/>
</bean>
<bean id="service2" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
    <property name="desc" value="service2"/>
</bean>
<bean id="service2-1" class="com.javacode2018.lesson001.demo6.DiAutowireByName$Service2">
    <property name="desc" value="service2-1"/>
</bean>

<!-- autowire:byName 配置按照name进行自动注入 -->
<bean id="diAutowireByName1" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName"/>

<!-- 当配置了自动注入,还可以使用手动的方式自动注入进行覆盖,手动的优先级更高一些 -->
<bean id="diAutowireByName2" class="com.javacode2018.lesson001.demo6.DiAutowireByName" autowire="byName">
    <property name="service2" ref="service2-1"/>
</bean>

上面注释认真看一下。

@1:定义了一个名称为service1的bean

@2:定义了一个名称为service2的bean

@3:定义diAutowireByName需要将autowire的值置为byName,表示按名称进行自动注入。

spring容器创建diAutowireByName对应的bean时,会遍历DiAutowireByName类中的所有set方法,然后得到set对应的属性名称列表:{“service1”,“service2”},然后遍历这属性列表,在容器中查找和属性同名的bean对象,然后调用属性对应的set方法,将bean对象注入进去

测试用例

DiAutowireTest类中添加一个方法

/**

  • 按照set方法参数类型进行注入
    */
    @Test
    public void diAutowireByType() {
    String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByType.xml”;
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    System.out.println(context.getBean(“diAutowireByType1”));
    }

效果

运行diAutowireByType输出:

setService1->Service1{desc=‘service1’}
setService2->Service2{desc=‘service2’}
DiByType{service1=Service1{desc=‘service1’}, service2=Service2{desc=‘service2’}}


## 优缺点

相对于手动注入,节省了不少代码,新增或者删除属性,只需要增减对应的set方法就可以了,更容易扩展了。

## 注入类型匹配的所有bean(重点)

按照类型注入还有2中比较牛逼的用法:

一个容器中满足某种类型的bean可以有很多个,将容器中某种类型中的所有bean,通过set方法注入给一个java.util.List<需要注入的Bean的类型或者其父类型或者其接口>对象

将容器中某种类型中的所有bean,通过set方法注入给一个java.util.Map<String,需要注入的Bean的类型或者其父类型或者其接口>对象

来看个案例就懂了。

DiAutowireByTypeExtend.java

package com.javacode2018.lesson001.demo6;

import java.util.List;
import java.util.Map;

/**

  • 满足条件的bean注入到集合中(重点)
    */
    public class DiAutowireByTypeExtend {

    //定义了一个接口
    public interface IService1 {
    }

    public static class BaseServie {
    private String desc;

     public String getDesc() {
         return desc;
     }
    
     public void setDesc(String desc) {
         this.desc = desc;
     }
    
     @Override
     public String toString() {
         return "BaseServie{" +
                 "desc='" + desc + '\'' +
                 '}';
     }
    

    }

    //Service1实现了IService1接口
    public static class Service1 extends BaseServie implements IService1 {

    }

    //Service1实现了IService1接口
    public static class Service2 extends BaseServie implements IService1 {
    }

    private List serviceList;//@1
    private List baseServieList;//@2
    private Map<String, IService1> service1Map;//@3
    private Map<String, BaseServie> baseServieMap;//@4

    public List getServiceList() {
    return serviceList;
    }

    public void setServiceList(List serviceList) {//@5
    this.serviceList = serviceList;
    }

    public List getBaseServieList() {
    return baseServieList;
    }

    public void setBaseServieList(List baseServieList) {//@6
    this.baseServieList = baseServieList;
    }

    public Map<String, IService1> getService1Map() {
    return service1Map;
    }

    public void setService1Map(Map<String, IService1> service1Map) {//@7
    this.service1Map = service1Map;
    }

    public Map<String, BaseServie> getBaseServieMap() {
    return baseServieMap;
    }

    public void setBaseServieMap(Map<String, BaseServie> baseServieMap) {//@8
    this.baseServieMap = baseServieMap;
    }

    @Override
    public String toString() { //9
    return “DiAutowireByTypeExtend{” +
    “serviceList=” + serviceList +
    “, baseServieList=” + baseServieList +
    “, service1Map=” + service1Map +
    “, baseServieMap=” + baseServieMap +
    ‘}’;
    }
    }


@1,@2,@3,@4:定义了4个属性,都是泛型类型的,都有对应的set方法。

@5:参数类型是List,这个集合集合中元素的类型是BaseServie,spring会找到容器中所有满足BaseServie.isAssignableFrom(bean的类型)的bean列表,将其通过@5的set方法进行注入。

@6:同@5的代码

@7:这个参数类型是一个map了,map的key是string类型,value是IService1类型,spring容器会将所有满足IService1类型的bean找到,按照name->bean对象这种方式丢到一个map中,然后调用@7的set方法进行注入,最后注入的这个map就是bean的名称和bean对象进行映射的一个map对象。

@8:同@7的代码

@9:重写了toString方法,输出的时候好看一些

测试用例

DiAutowireTest新增一个方法:

/**

  • 按照类型注入集合
    */
    @Test
    public void diAutowireByTypeExtend() {
    String beanXml = “classpath:/com/javacode2018/lesson001/demo6/diAutowireByTypeExtend.xml”;
    ClassPathXmlApplicationContext context = IocUtils.context(beanXml);
    //从容器中获取DiAutowireByTypeExtend
    DiAutowireByTypeExtend diAutowireByTypeExtend = context.getBean(DiAutowireByTypeExtend.class);
    //输出diAutowireByTypeExtend中的属性看一下
    System.out.println(“serviceList:” + diAutowireByTypeExtend.getServiceList());
    System.out.println(“baseServieList:” + diAutowireByTypeExtend.getBaseServieList());
    System.out.println(“service1Map:” + diAutowireByTypeExtend.getService1Map());
    System.out.println(“baseServieMap:” + diAutowireByTypeExtend.getBaseServieMap());
    }

效果

运行diAutowireByTypeExtend输出:

serviceList:[BaseServie{desc=‘service1-1’}, BaseServie{desc=‘service1-2’}, BaseServie{desc=‘service2-1’}]
baseServieList:[BaseServie{desc=‘service1-1’}, BaseServie{desc=‘service1-2’}, BaseServie{desc=‘service2-1’}]
service1Map:{service1-1=BaseServie{desc=‘service1-1’}, service1-2=BaseServie{desc=‘service1-2’}, service2-1=BaseServie{desc=‘service2-1’}}
baseServieMap:{service1-1=BaseServie{desc=‘service1-1’}, service1-2=BaseServie{desc=‘service1-2’}, service2-1=BaseServie{desc=‘service2-1’}}


下面我们来介绍另外一种自动注入方式。

# 按照构造函数进行自动注入

## 用法

autowire设置为constructor


spring会找到x类中所有的构造方法(一个类可能有多个构造方法),然后将这些构造方法进行排序(先按修饰符进行排序,public的在前面,其他的在后面,如果修饰符一样的,会按照构造函数参数数量倒叙,也就是采用贪婪的模式进行匹配,spring容器会尽量多注入一些需要的对象)得到一个构造函数列表,会轮询这个构造器列表,判断当前构造器所有参数是否在容器中都可以找到匹配的bean对象,如果可以找到就使用这个构造器进行注入,如果不能找到,那么就会跳过这个构造器,继续采用同样的方式匹配下一个构造器,直到找到一个合适的为止。

来看看案例吧。

## 案例

DiAutowireByConstructor.java

package com.javacode2018.lesson001.demo6;

/**

  • 构造函数的方式进行自动注入
    */
    public class DiAutowireByConstructor {

    public static class BaseServie {
    private String desc;

     public String getDesc() {
         return desc;
     }
    
     public void setDesc(String desc) {
         this.desc = desc;
     }
    
     @Override
     public String toString() {
         return "BaseServie{" +
                 "desc='" + desc + '\'' +
                 '}';
     }
    

    }

    //Service1实现了IService1接口
    public static class Service1 extends BaseServie {
    }

    //Service1实现了IService1接口
    public static class Service2 extends BaseServie {
    }

    private Service1 service1;

最后分享一波我的面试宝典——一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

点击《一线互联网大厂Java核心面试题库》即可免费领取,整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

image

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

image

还有源码相关的阅读学习

image

gitee.com/vip204888/java-p7)**,整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

[外链图片转存中…(img-XcCyT5c5-1628066927584)]

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

[外链图片转存中…(img-ELZfFGDa-1628066927587)]

还有源码相关的阅读学习

[外链图片转存中…(img-pCbw7ztn-1628066927588)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值