Spring系列第21篇:注解实现依赖注入(@Autowired、@Resource、@Primary、

概括为:先按类型找,然后按名称找

案例1:@Autowired标注在构造器上,通过构造器注入依赖对象

Service1

package com.javacode2018.lesson001.demo26.test0;

import org.springframework.stereotype.Component;

@Component

public class Service1 {

}

Service2

package com.javacode2018.lesson001.demo26.test0;

import org.springframework.stereotype.Component;

@Component

public class Service2 {

private Service1 service1;

public Service2() { //@1

System.out.println(this.getClass() + “无参构造器”);

}

public Service2(Service1 service1) { //@2

System.out.println(this.getClass() + “有参构造器”);

this.service1 = service1;

}

@Override

public String toString() { //@2

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

Service2中依赖于Service1,有2个构造方法

@1:无参构造器

@2:有参构造器,可以通过这个传入依赖的Service1

@3:重写了toString方法,一会打印测试的时候方便查看

来个总的配置文件

package com.javacode2018.lesson001.demo26.test0;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan //@1

public class MainConfig0 {

}

@1:会自动扫描当前类所在的包,会将Service1和Service2注册到容器。

来个测试用例

package com.javacode2018.lesson001.demo26;

import com.javacode2018.lesson001.demo26.test0.MainConfig0;

import org.junit.Test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class InjectTest {

@Test

public void test0() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig0.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

}

main方法中启动容器,加载MainConfig0配置类,然后输出容器中所有的bean

运行部分输出

class com.javacode2018.lesson001.demo26.test0.Service2无参构造器

service1->com.javacode2018.lesson001.demo26.test0.Service1@4a94ee4

service2->Service2{service1=null}

输出中可以看出调用了Service2的无参构造器,service2中的service1为null

通过@Autowired指定注入的构造器

在Service2有参有参构造器上面加上@Autowired注解,如下:

@Autowired

public Service2(Service1 service1) {

System.out.println(this.getClass() + “有参构造器”);

this.service1 = service1;

}

再次运行test0()

class com.javacode2018.lesson001.demo26.test0.Service2有参构造器

service1->com.javacode2018.lesson001.demo26.test0.Service1@4ec4f3a0

service2->Service2{service1=com.javacode2018.lesson001.demo26.test0.Service1@4ec4f3a0}

Service2有参构造器被调用了,service2中的service1有值了。

案例2:@Autowired标注在方法上,通过方法注入依赖的对象

Service1

package com.javacode2018.lesson001.demo26.test1;

import org.springframework.stereotype.Component;

@Component

public class Service1 {

}

Service2

package com.javacode2018.lesson001.demo26.test1;

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

import org.springframework.stereotype.Component;

@Component

public class Service2 {

private Service1 service1;

@Autowired

public void injectService1(Service1 service1) { //@1

System.out.println(this.getClass().getName() + “.injectService1()”);

this.service1 = service1;

}

@Override

public String toString() {

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

@1:方法上标注了@Autowired,spring容器会调用这个方法,从容器中查找Service1类型的bean,然后注入。

来个总的配置文件

package com.javacode2018.lesson001.demo26.test1;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig1 {

}

来个测试用例

InjectTest中加个方法

@Test

public void test1() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig1.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

com.javacode2018.lesson001.demo26.test1.Service2.injectService1()

service1->com.javacode2018.lesson001.demo26.test1.Service1@9597028

service2->Service2{service1=com.javacode2018.lesson001.demo26.test1.Service1@9597028}

通过injectService1方法成功注入service1

案例3:@Autowired标注在setter方法上,通过setter方法注入

上面2种通过构造器,和通过普通的一个方法注入,不是很常见,可以将@Autowired标注在set方法上面,来注入指定的对象

Service1

package com.javacode2018.lesson001.demo26.test2;

import org.springframework.stereotype.Component;

@Component

public class Service1 {

}

Service2

package com.javacode2018.lesson001.demo26.test2;

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

import org.springframework.stereotype.Component;

@Component

public class Service2 {

private Service1 service1;

@Autowired

public void setService1(Service1 service1) { //@1

System.out.println(this.getClass().getName() + “.setService1方法”);

this.service1 = service1;

}

@Override

public String toString() {

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

@1:标准的set方法,方法上使用了 @Autowired,会通过这个方法注入Service1类型的bean对象。

来个总的配置文件

package com.javacode2018.lesson001.demo26.test2;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig2 {

}

来个测试用例

@Test

public void test2() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

com.javacode2018.lesson001.demo26.test2.Service2.setService1方法

service1->com.javacode2018.lesson001.demo26.test2.Service1@6069db50

service2->Service2{service1=com.javacode2018.lesson001.demo26.test2.Service1@6069db50}

案例4:@Autowired标注在方法参数上

Service1

package com.javacode2018.lesson001.demo26.test3;

import org.springframework.stereotype.Component;

@Component

public class Service1 {

}

Service2

package com.javacode2018.lesson001.demo26.test3;

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

import org.springframework.stereotype.Component;

@Component

public class Service2 {

private Service1 service1;

@Autowired

public void injectService1(Service1 service1, String name) { //@1

System.out.println(String.format(“%s.injectService1(),{service1=%s,name=%s}”, this.getClass().getName(), service1, name));

this.service1 = service1;

}

@Override

public String toString() {

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

@1:方法上标注了@Autowired,表示会将这个方法作为注入方法,这个方法有2个参数,spring查找这2个参数对应的bean,然后注入。

第一个参数对应的bean是存在的,第二个是一个String类型的,我们并没有定义String类型bean,一会看看效果

来个总的配置文件

package com.javacode2018.lesson001.demo26.test3;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig3 {

}

来个测试用例

@Test

public void test3() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig3.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘service2’: Unsatisfied dependency expressed through method ‘injectService1’ parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘java.lang.String’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

报错了,从错误信息中可以看出,通过injectService1方法注入的时候,第二个参数为String类型,spring从容器中没有找到String类型的候选bean,所以报错了。

我们可以这么做

多个参数的时候,方法上面的@Autowire默认对方法中所有参数起效,如果我们想对某个参数进行特定的配置,可以在参数上加上@Autowired,这个配置会覆盖方法上面的@Autowired配置。

在第二个参数上面加上@Autowired,设置required为false:表示这个bean不是强制注入的,能找到就注入,找不到就注入一个null对象,调整一下代码,如下:

@Autowired

public void injectService1(Service1 service1, @Autowired(required = false) String name) { //@1

System.out.println(String.format(“%s.injectService1(),{service1=%s,name=%s}”, this.getClass().getName(), service1, name));

this.service1 = service1;

}

此时方法的第一个参数被方法上面的@Autowired约束

第二个参数受@Autowired(required = false)约束

再次运行输出

com.javacode2018.lesson001.demo26.test3.Service2.injectService1(),{service1=com.javacode2018.lesson001.demo26.test3.Service1@59309333,name=null}

service1->com.javacode2018.lesson001.demo26.test3.Service1@59309333

service2->Service2{service1=com.javacode2018.lesson001.demo26.test3.Service1@59309333}

注入成功了,service1有值,name为null

案例5:@Autowired用在字段上

Service1

package com.javacode2018.lesson001.demo26.test4;

import org.springframework.stereotype.Component;

@Component

public class Service1 {

}

Service2

package com.javacode2018.lesson001.demo26.test4;

import org.springframework.stereotype.Component;

@Component

public class Service2 {

}

Service3

package com.javacode2018.lesson001.demo26.test4;

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

import org.springframework.stereotype.Component;

@Component

public class Service3 {

@Autowired

private Service1 service1;//@1

@Autowired

private Service2 service2;//@2

@Override

public String toString() {

return “Service3{” +

“service1=” + service1 +

“, service2=” + service2 +

‘}’;

}

}

@1和@2:定义了2个字段,上面都标注了@Autowired,spring会去容器中按照类型查找这2种类型的bean,然后设置给这2个属性。

来个总的配置文件

package com.javacode2018.lesson001.demo26.test4;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig4 {

}

来个测试用例

@Test

public void test4() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig4.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

service1->com.javacode2018.lesson001.demo26.test4.Service1@7e07db1f

service2->com.javacode2018.lesson001.demo26.test4.Service2@1189dd52

service3->Service3{service1=com.javacode2018.lesson001.demo26.test4.Service1@7e07db1f, service2=com.javacode2018.lesson001.demo26.test4.Service2@1189dd52}

service3中标注@Autowired的2个属性都有值了,都被注入成功了。

案例6:@Autowire标注字段,多个候选者的时候,按字段名称注入

IService接口

package com.javacode2018.lesson001.demo26.test5;

public interface IService {

}

接口来2个实现

2个实现类上都标注了@Component注解,都会被注册到容器中。

Service0

package com.javacode2018.lesson001.demo26.test5;

import org.springframework.stereotype.Component;

@Component

public class Service0 implements IService {

}

Service1

package com.javacode2018.lesson001.demo26.test5;

import org.springframework.stereotype.Component;

@Component

public class Service1 implements IService {

}

来个Service2

package com.javacode2018.lesson001.demo26.test5;

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

import org.springframework.stereotype.Component;

@Component

public class Service2 {

@Autowired

private IService service1; //@1

@Override

public String toString() {

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

@1:标注了@Autowired注解,需要注入类型为IService类型的bean,满足这种类型的有2个:service0和service1

按照上面介绍的候选者查找过程,最后会注入和字段名称一样的bean,即:service1

来个总的配置类,负责扫描当前包中的组件

package com.javacode2018.lesson001.demo26.test5;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig5 {

}

来个测试用例

@Test

public void test5() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig5.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

service0->com.javacode2018.lesson001.demo26.test5.Service0@36902638

service1->com.javacode2018.lesson001.demo26.test5.Service1@223d2c72

service2->Service2{service1=com.javacode2018.lesson001.demo26.test5.Service1@223d2c72}

注意最后一行,service2中的service1被注入了bean:service1

案例7:将指定类型的所有bean,注入到Collection、Map中

注入到Collection中

被注入的类型为Collection类型或者Collection子接口类型,注意必须是接口类型,如:

Collection

List

Set

会在容器中找到所有IService类型的bean,放到这个集合中

注入到Map中

被注入的类型为Map类型或者Map子接口类型,注意必须是接口类型,如:

Map<String,IService>

会在容器中找到所有IService类型的bean,放到这个Map中,key为bean的名称,value为bean对象

来看案例代码。

来个接口

package com.javacode2018.lesson001.demo26.test6;

public interface IService {

}

来2个实现类,标注@Component注解

Service0

package com.javacode2018.lesson001.demo26.test6;

import org.springframework.stereotype.Component;

@Component

public class Service0 implements IService {

}

Service1

package com.javacode2018.lesson001.demo26.test6;

import org.springframework.stereotype.Component;

@Component

public class Service1 implements IService {

}

再来个类Service2

package com.javacode2018.lesson001.demo26.test6;

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

import org.springframework.stereotype.Component;

import java.util.List;

import java.util.Map;

@Component

public class Service2 {

@Autowired

private List services;

@Autowired

private Map<String, IService> serviceMap;

@Override

public String toString() {

return “Service2{\n” +

“services=” + services +

“, \n serviceMap=” + serviceMap +

‘}’;

}

}

@1:注入IService类型的所有bean

@2:注入一个map

来个总的配置类

package com.javacode2018.lesson001.demo26.test6;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig6 {

}

来个测试用例

@Test

public void test6() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig6.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

service0->com.javacode2018.lesson001.demo26.test6.Service0@1189dd52

service1->com.javacode2018.lesson001.demo26.test6.Service1@36bc55de

service2->Service2{

services=[com.javacode2018.lesson001.demo26.test6.Service0@1189dd52, com.javacode2018.lesson001.demo26.test6.Service1@36bc55de],

serviceMap={service0=com.javacode2018.lesson001.demo26.test6.Service0@1189dd52, service1=com.javacode2018.lesson001.demo26.test6.Service1@36bc55de}}

注意看一下上面services和serviceMap的值。

@Autowired源码

spring使用下面这个类处理@Autowired注解

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor

@Resource:注意依赖对象


作用

和@Autowired注解类似,也是用来注入依赖的对象的,spring容器会对bean中所有字段、方法进行遍历,标注有@Resource注解的,都会进行注入。

看一下这个注解定义:

javax.annotation.Resource

@Target({TYPE, FIELD, METHOD})

@Retention(RUNTIME)

public @interface Resource {

String name() default “”;

…其他不常用的参数省略

}

这个注解是javax中定义的,并不是spring中定义的注解。

从定义上可以见,这个注解可以用在任何类型上面、字段、方法上面。

注意点:

用在方法上的时候,方法参数只能有一个。

@Resource查找候选者的过程

查找过程有点复杂,看不懂的可以先跳过,先看后面案例,本文看完之后,可以回头再来看这个过程。

@Resource标注在字段上面:假定字段类型为一个自定义的普通的类型,候选者查找过程如下

@Autowired标注在方法上或者方法参数上面:假定参数类型为为一个自定义的普通的类型,候选者查找过程如下:

将指定类型的所有bean注入到Collection中

如果被注入的对象是Collection类型的,可以指定泛型的类型,然后会按照上面的方式查找所有满足泛型类型所有的bean

将指定类型的所有bean注入到Map中

如果被注入的对象是Map类型的,可以指定泛型的类型,key通常为String类型,value为需要查找的bean的类型,然后会按照上面方式查找所有注入value类型的bean,将bean的name作为key,bean对象作为value,放在HashMap中,然后注入。

@Resource查找候选者可以简化为

先按Resource的name值作为bean名称找->按名称(字段名称、方法名称、set属性名称)找->按类型找->通过限定符@Qualifier过滤->@Primary->@Priority->根据名称找(字段名称或者方法参数名称)

概括为:先按名称找,然后按类型找

案例1:将@Resource标注在字段上

IService接口

package com.javacode2018.lesson001.demo26.test7;

public interface IService {

}

2个实现类

Service0

package com.javacode2018.lesson001.demo26.test7;

import org.springframework.stereotype.Component;

@Component

public class Service0 implements IService {

}

@Component标注的bean名称默认为service0

Service1

package com.javacode2018.lesson001.demo26.test7;

import org.springframework.stereotype.Component;

@Component

public class Service1 implements IService {

}

@Component标注的bean名称默认为service1

再来一个类

package com.javacode2018.lesson001.demo26.test7;

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

import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.List;

import java.util.Map;

@Component

public class Service2 {

@Resource

private IService service1;//@1

@Override

public String toString() {

return “Service2{” +

“service1=” + service1 +

‘}’;

}

}

@1:字段名称为service1,按照字段名称查找bean,会找到Service1

来个配置类

package com.javacode2018.lesson001.demo26.test7;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig7 {

}

测试用例

@Test

public void test7() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig7.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

service0->com.javacode2018.lesson001.demo26.test7.Service0@222545dc

service1->com.javacode2018.lesson001.demo26.test7.Service1@5c5eefef

service2->Service2{service1=com.javacode2018.lesson001.demo26.test7.Service1@5c5eefef}

最后一行可以看出注入了service1

如果将Service2中的代码调整一下

@Resource

private IService service0;

此时会注入service0这个bean

同样@Resource可以用在方法上,也可以将所有类型的bean注入到Collection、Map中,这里就不演示了,重点了解一下候选者查找的过程,使用上就比较简单了,@Resource的其他案例,大家可以自己写写练练。

下面来说另外几个注解,也是比较重要的。

@Resource源码

spring使用下面这个类处理@Resource注解

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

@Qualifier:限定符


作用

这个单词的意思是:限定符。

可以在依赖注入查找候选者的过程中对候选者进行过滤。

看一下其定义:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Inherited

@Documented

public @interface Qualifier {

String value() default “”;

}

可以用在字段、方法、参数、任意类型、注解上面

有一个参数value

还是来看案例,通过案例理解更容易。

案例1:用在类上

用在类上,你可以理解为给通过@Qulifier给这个bean打了一个标签。

先来一个接口

package com.javacode2018.lesson001.demo26.test8;

public interface IService {

}

来3个实现类

前2个@Qulifier的value为tag1,第3个实现类为tag2

Service1

package com.javacode2018.lesson001.demo26.test8;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

@Qualifier(“tag1”) //@1

public class Service1 implements IService {

}

@1:tag1

Service2

package com.javacode2018.lesson001.demo26.test8;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

@Qualifier(“tag1”)

public class Service2 implements IService {

}

@1:tag1

Service3

package com.javacode2018.lesson001.demo26.test8;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

@Qualifier(“tag2”)//@1

public class Service3 implements IService {

}

@1:tag2

来一个类,来注入上面几个bean

package com.javacode2018.lesson001.demo26.test8;

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

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

import java.util.Map;

@Component

public class InjectService {

@Autowired

@Qualifier(“tag1”) //@1

private Map<String, IService> serviceMap1;

@Autowired

@Qualifier(“tag2”) //@2

private Map<String, IService> serviceMap2;

@Override

public String toString() {

return “InjectService{” +

“serviceMap1=” + serviceMap1 +

“, serviceMap2=” + serviceMap2 +

‘}’;

}

}

@1:限定符的值为tag1,此时会将类上限定符为tag1的所有bean注入进来

@2:限定符的值为tag2,此时会将类上限定符为tag2的所有bean注入进来

来个配置类

package com.javacode2018.lesson001.demo26.test8;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig8 {

}

测试用例

@Test

public void test8() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig8.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{serviceMap1={service1=com.javacode2018.lesson001.demo26.test8.Service1@9597028, service2=com.javacode2018.lesson001.demo26.test8.Service2@6069db50}, serviceMap2={service3=com.javacode2018.lesson001.demo26.test8.Service3@4efbca5a}}

service1->com.javacode2018.lesson001.demo26.test8.Service1@9597028

service2->com.javacode2018.lesson001.demo26.test8.Service2@6069db50

service3->com.javacode2018.lesson001.demo26.test8.Service3@4efbca5a

注意第一行的输出,看一下serviceMap1和serviceMap2的值。

serviceMap1注入了@Qulifier的value为tag1的所有IService类型的bean

serviceMap1注入了@Qulifier的value为tag2的所有IService类型的bean

实现了bean分组的效果。

案例2:@Autowired结合@Qulifier指定注入的bean

被注入的类型有多个的时候,可以使用@Qulifier来指定需要注入那个bean,将@Qulifier的value设置为需要注入bean的名称

看案例代码

来个接口

package com.javacode2018.lesson001.demo26.test9;

public interface IService {

}

有2个实现类

2个实现类上面没有使用@Qulifier注解了

Service1

package com.javacode2018.lesson001.demo26.test9;

import org.springframework.stereotype.Component;

@Component

public class Service1 implements IService {

}

Service2

package com.javacode2018.lesson001.demo26.test9;

import org.springframework.stereotype.Component;

@Component

public class Service2 implements IService {

}

我们可以知道上面2个bean的名称分别为:service1、service2

来个类,注入IService类型的bean

package com.javacode2018.lesson001.demo26.test9;

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

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

public class InjectService {

@Autowired

@Qualifier(“service2”) //@1

private IService service;

@Override

public String toString() {

return “InjectService{” +

“service=” + service +

‘}’;

}

}

@1:这里限定符的值为service2,容器中IService类型的bean有2个[service1和service2],当类上没有标注@Qualifier注解的时候,可以理解为:bean的名称就是限定符的值,所以@1这里会匹配到service2

来个配置类

package com.javacode2018.lesson001.demo26.test9;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.stereotype.Component;

@ComponentScan

public class MainConfig9 {

}

来个测试用例

@Test

public void test9() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig9.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{service=com.javacode2018.lesson001.demo26.test9.Service2@223d2c72}

service1->com.javacode2018.lesson001.demo26.test9.Service1@8f4ea7c

service2->com.javacode2018.lesson001.demo26.test9.Service2@223d2c72

从第一行可以看出注入了service1

案例3:用在方法参数上

代码

package com.javacode2018.lesson001.demo26.test10;

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

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

public class InjectService {

private IService s1;

private IService s2;

@Autowired

public void injectBean(@Qualifier(“service2”) IService s1, @Qualifier(“service1”) IService s2) { //@1

this.s1 = s1;

this.s2 = s2;

}

@Override

public String toString() {

return “InjectService{” +

“s1=” + s1 +

“, s2=” + s2 +

‘}’;

}

}

@1:方法上标注了@Autowired注解,说明会被注入依赖,2个参数上分别使用了限定符来指定具体需要注入哪个bean

测试用例

@Test

public void test10() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig10.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{s1=com.javacode2018.lesson001.demo26.test10.Service2@55183b20, s2=com.javacode2018.lesson001.demo26.test10.Service1@4f83df68}

service1->com.javacode2018.lesson001.demo26.test10.Service1@4f83df68

service2->com.javacode2018.lesson001.demo26.test10.Service2@55183b20

第一行中的

s1:service2

s2:service1

案例4:用在setter方法上

不管是用在setter方法还是普通方法上面,都是一样的效果

代码

package com.javacode2018.lesson001.demo26.test11;

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

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.stereotype.Component;

@Component

public class InjectService {

private IService s1;

private IService s2;

@Autowired

@Qualifier(“service2”)

public void setS1(IService s1) {

this.s1 = s1;

}

@Autowired

@Qualifier(“service2”)

public void setS2(IService s2) {

this.s2 = s2;

}

@Override

public String toString() {

return “InjectService{” +

“s1=” + s1 +

“, s2=” + s2 +

‘}’;

}

}

上面2个setter方法上都有@Autowired注解,并且结合了@Qulifier注解来限定需要注入哪个bean

测试用例

@Test

public void test11() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig11.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{s1=com.javacode2018.lesson001.demo26.test11.Service2@35e2d654, s2=com.javacode2018.lesson001.demo26.test11.Service2@35e2d654}

service1->com.javacode2018.lesson001.demo26.test11.Service1@1bd4fdd

service2->com.javacode2018.lesson001.demo26.test11.Service2@35e2d654

输出中可以看出:s1为service2,s2为service1

@Primary:设置为主要候选者


注入依赖的过程中,当有多个候选者的时候,可以指定哪个候选者为主要的候选者。

看一下其定义

@Target({ElementType.TYPE, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Primary {

}

可以用在类上或者方法上面。

通常定义bean常见的有2种方式:

方式1:在类上标注@Component注解,此时可以配合@Primary,标注这个bean为主要候选者

方式2:在配置文件中使用@Bean注解标注方法,来注册bean,可以在@Bean标注的方法上加上@Primary,标注这个bean为主要候选bean。

看案例。

案例1:用在类上

来个接口

package com.javacode2018.lesson001.demo26.test12;

public interface IService {

}

2个实现类

Service1

package com.javacode2018.lesson001.demo26.test12;

import org.springframework.stereotype.Component;

@Component

public class Service1 implements IService {

}

Service2

package com.javacode2018.lesson001.demo26.test12;

import org.springframework.context.annotation.Primary;

import org.springframework.stereotype.Component;

@Component

@Primary

public class Service2 implements IService {

}

Service2上面使用了@Primary,表示这是个主要的候选者

再来个类,注入IService类型的bean

package com.javacode2018.lesson001.demo26.test12;

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

import org.springframework.stereotype.Component;

@Component

public class InjectService {

@Autowired

private IService service1; //@1

@Override

public String toString() {

return “InjectService{” +

“service1=” + service1 +

‘}’;

}

}

@1:容器中IService类型的bean有2个,但是service2为主要的候选者,所以此处会注入service2

总的配置类

package com.javacode2018.lesson001.demo26.test12;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig12 {

}

测试用例

@Test

public void test12() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig12.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{service1=com.javacode2018.lesson001.demo26.test12.Service2@49ec71f8}

service1->com.javacode2018.lesson001.demo26.test12.Service1@1d2adfbe

service2->com.javacode2018.lesson001.demo26.test12.Service2@49ec71f8

案例2:用在方法上,结合@Bean使用

来个接口

package com.javacode2018.lesson001.demo26.test13;

public interface IService {

}

2个实现类

Service1

package com.javacode2018.lesson001.demo26.test13;

public class Service1 implements IService {

}

Service2

package com.javacode2018.lesson001.demo26.test13;

public class Service2 implements IService {

}

InjectService

package com.javacode2018.lesson001.demo26.test13;

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

public class InjectService {

@Autowired

private IService service1;//@1

@Override

public String toString() {

return “InjectService{” +

“service1=” + service1 +

‘}’;

}

}

使用了@Autowired,需要注入

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
vice1 implements IService {

}

Service2

package com.javacode2018.lesson001.demo26.test12;

import org.springframework.context.annotation.Primary;

import org.springframework.stereotype.Component;

@Component

@Primary

public class Service2 implements IService {

}

Service2上面使用了@Primary,表示这是个主要的候选者

再来个类,注入IService类型的bean

package com.javacode2018.lesson001.demo26.test12;

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

import org.springframework.stereotype.Component;

@Component

public class InjectService {

@Autowired

private IService service1; //@1

@Override

public String toString() {

return “InjectService{” +

“service1=” + service1 +

‘}’;

}

}

@1:容器中IService类型的bean有2个,但是service2为主要的候选者,所以此处会注入service2

总的配置类

package com.javacode2018.lesson001.demo26.test12;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan

public class MainConfig12 {

}

测试用例

@Test

public void test12() {

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig12.class);

for (String beanName : context.getBeanDefinitionNames()) {

System.out.println(String.format(“%s->%s”, beanName, context.getBean(beanName)));

}

}

运行输出

injectService->InjectService{service1=com.javacode2018.lesson001.demo26.test12.Service2@49ec71f8}

service1->com.javacode2018.lesson001.demo26.test12.Service1@1d2adfbe

service2->com.javacode2018.lesson001.demo26.test12.Service2@49ec71f8

案例2:用在方法上,结合@Bean使用

来个接口

package com.javacode2018.lesson001.demo26.test13;

public interface IService {

}

2个实现类

Service1

package com.javacode2018.lesson001.demo26.test13;

public class Service1 implements IService {

}

Service2

package com.javacode2018.lesson001.demo26.test13;

public class Service2 implements IService {

}

InjectService

package com.javacode2018.lesson001.demo26.test13;

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

public class InjectService {

@Autowired

private IService service1;//@1

@Override

public String toString() {

return “InjectService{” +

“service1=” + service1 +

‘}’;

}

}

使用了@Autowired,需要注入

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-08bmcmD0-1715093789739)]

[外链图片转存中…(img-orrQWJv5-1715093789740)]

[外链图片转存中…(img-eDzjw8Kx-1715093789740)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值