本文最后更新于:June 13, 2022 pm
Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。
目录
源码 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { boolean required () default true ; }
@Autowired 会先根据类型进行查找,然后再根据名称进行查找。
类型注入 目标Bean:
package com.SpringTestAnnotation.TestValue;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class OrderS { }
默认名称为:orderS。
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { @Autowired private OrderS orderS111; public void show () { System.out.println("Per show " +orderS111); } }
可以看见,除了类型为OrderS,名称是对不上的。
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.SpringTestAnnotation;import com.SpringTestAnnotation.TestValue.Per;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestAnnotation { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class); Per per = applicationContext.getBean("per" , Per.class); per.show(); } }
这样是成功运行的。所以,默认就是用的类型进行注入。而名称是无所谓的。但是,当同一个类型有多个时,就必须要指明名称了。
名称注入 注入失败
当同一类型有多个时,任意写名称。
目标Bean:
package com.SpringTestAnnotation.TestValue;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class OrderS { }
配置类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.SpringTestAnnotation;import com.SpringTestAnnotation.TestValue.OrderS;import com.SpringTestAnnotation.TestValue.OurAnno;import com.SpringTestAnnotation.TestValue.Per;import org.springframework.beans.factory.annotation.Autowire;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.*;import org.springframework.stereotype.Component;@ComponentScan(value = "com.SpringTestAnnotation") public class TestConfig { @Bean public OrderS orderS () { return new OrderS(); } @Bean public OrderS orderS1 () { return new OrderS(); } @Bean public OrderS orderS2 () { return new OrderS(); } }
这里配置了同一类型的三个不同名称的Bean。
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { @Autowired private OrderS orderS111; public void show () { System.out.println("Per show " +orderS111); } }
这里的名称在容器中并没有。
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.SpringTestAnnotation;import com.SpringTestAnnotation.TestValue.Per;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class TestAnnotation { public static void main (String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class); Per per = applicationContext.getBean("per" , Per.class); per.show(); } }
运行报错如下:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'per' : Unsatisfied dependency expressed through field 'orderS111' ; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.SpringTestAnnotation.TestValue.OrderS' available: expected single matching bean but found 3 : orderS,orderS1,orderS2
大概意思说:找到的类型中只有这三个名称的Bean:orderS,orderS1,orderS2。对于要注入的Bean名称为orderS111的并没有。
注入成功 代码同上,修改一个地方即可:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { @Autowired private OrderS orderS; public void show () { System.out.println("Per show " +orderS); } }
其中,属性的名称可以为:orderS,orderS1,orderS2三个中的任意一个。
setter注入 在上面代码的基础上修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; @Autowired public void setOrderS1 (OrderS orderS1) { this .orderS1 = orderS1; } public void show () { System.out.println("Per show " +orderS1); } }
原理同在属性上使用@Autowired一样,会先根据类型注入,然后再根据名称进行注入。这里的类型值的是参数里面的类型,名称是参数里面的名称,即:public void setOrderS1(OrderS orderS1)
这里面的类型和名称。
📢注意:
在这里!仅限在这里!(和被static修饰不一样)方法的名称可以任意写,不用写setXxxx什么之类的,最后都会根据参数进行匹配,然后再进行调用。如下:(正常运行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; @Autowired public void asdf (OrderS orderS1) { this .orderS1 = orderS1; } public void show () { System.out.println("Per show " +orderS1); } }
测试代码同上。
方法没有参数,方法
依旧可以执行。只是最后Bean输出的是null而已。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; @Autowired public void asdf () { System.out.println("Per Bean" ); } public void show () { System.out.println("Per show " +orderS1); } }
测试代码同上。输出结果:
信息: Autowired annotation should only be used on methods with parameters: public void com.SpringTestAnnotation.TestValue.Per.asdf() Per Bean Per show null
构造注入 示例一 代码都同上,只写改变的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; public Per () { System.out.println("无参" ); } public Per (OrderS orderS1) { System.out.println("有参" ); this .orderS1 = orderS1; } public void show () { System.out.println("Per show " +orderS1); } }
测试输出:
可以发现,Spring调用的是无参构造方法。
示例二 再如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; public Per (OrderS orderS1) { System.out.println("有参1" ); this .orderS1 = orderS1; } public Per (OrderS orderS,OrderS orderS1) { System.out.println("有参2" ); this .orderS1 = orderS1; } public void show () { System.out.println("Per show " +orderS1); } }
在这种情况下测试运行后,Spring不会用任何一个构造方法,会出现报错情况,如下:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'per' defined in file [/Users/dragonone/IdeaProjects/SpringStudy/Study001_DoubleBegin/Spring1_28/target/classes/com/SpringTestAnnotation/TestValue/Per.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.SpringTestAnnotation.TestValue.Per]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.SpringTestAnnotation.TestValue.Per.<init>()
原因:因为有两个构造方法,而Spring不知道使用哪一个,然后就会尝试去用无参的构造方法,但是又没有无参构造方法,所以就找不到而报错。也就是说,当Spring不知道选用哪一个构造方法时,就会去选用无参构造方法。
在Spring不知道使用哪一个构造方法时,我们可以指定使用哪一个。使用@Autowired注解指明使用哪一个构造方法,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { private OrderS orderS1; @Autowired public Per (OrderS orderS1) { System.out.println("有参1" ); this .orderS1 = orderS1; } public Per (OrderS orderS,OrderS orderS1) { System.out.println("有参2" ); this .orderS1 = orderS1; } public void show () { System.out.println("Per show " +orderS1); } }
测试输出:
有参1 Per show com.SpringTestAnnotation.TestValue.OrderS@44f75083
@Autowired还可以写在方法参数的前面,但是写了是没什么用的。具体可以见源码中的注释。
自定义注解 除了上面的用法之外,还可以用在自定义注解上面。在前面的有关注解的博客中,多次使用过自定义注解。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Scope;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) @Autowired public @interface OurAnno { }
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { @OurAnno private OrderS orderS1; public void show () { System.out.println("Per show " +orderS1); } }
这样一样的可以实现注入效果。
static修饰属性 当@Autowired作用于被static修饰的属性或方法时,是不会生效的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.SpringTestAnnotation.TestValue;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Conditional;import org.springframework.stereotype.Component;@Component public class Per { @Autowired private static OrderS orderS1; public void show () { System.out.println("Per show " +orderS1); } }
测试输出:
信息: Autowired annotation is not supported on static fields: private static com.SpringTestAnnotation.TestValue.OrderS com.SpringTestAnnotation.TestValue.Per.orderS1 Per show null
提示信息也说明了:@Autowired不支持写在一个static的字段上。
不支持用于static的原因:当Bean声明为@Scope(“prototype”)多例,而且也有多处进行注入,那么这多处的注入最后都是以最后一次的注入为最后结果的,即都是用的同一个。所以,多个注入间是相互影响的。