注解
0.注解定义
1.Annotation即注解(也被翻译为注释)
- 所有的注解会自动继承
java.lang.annotation.Annotation
(这个接口是一个常规接口,并非一个注解接口),并不能继承别的类或是接口 - 当一个注解的内部只有一个,且字段为value时,在使用的时候可以省略
2.自定义注解的使用:代码仓库见下
https://gitee.com/gqxm/gq-practice-glodon.git
- 自定义注解的简单使用:主要对ElementType.TYPE,METHOD,FIELD,PARAMETER等进行了测试和使用
- 自定义注解的简单使用:自定义NeedLogin注解,并且通过拦截器对其进行测试
1.jdk标准注解
1.元注解
JDK在java.lang.annotation
包下提供了6个Meta注解(元注解),其中5个用于修饰其他的注解定义。
注解 | 作用 |
---|---|
@Target | 用于指定被修饰的注解能用于修饰哪些程序单元(ElementType )。一个没有被此注解限制的注解可以应用于任何项上。 |
@Retention | 用于指定被修饰的注解可以保留多长时间。当未使用该注解修饰时,默认值相当于是RetentionPolicy.CLASS |
@Documented | 修饰注解类表明其将被javadoc工具提取成文档 |
@Inherited | 修饰作用于类的注解,指定被修饰的注解具有继承性:即该注解修饰的类的子类也将同样被该注解修饰 |
@Repeatable | 指明被修饰的这个注解可以在同一个元素上应用多次 |
@Native | 修饰成员变量,表示这个变量可以被本地代码引用,常常被代码生成工具使用(此注解不常用,了解即可) |
将一个注解应用到它自身上是合法的。例如,@Documented
注解被自身为注解为@Documented
。因此,针对注解的Javadoc文件可以表明它们是否可被归档。
1.@Target
ElementType
关于程序单元的枚举类型ElementType
:
TYPE
:类、接口、注解、枚举FIELD
:字段(含枚举值)METHOD
:方法PARAMETER
:形参(Formal parameter declaration)CONSTRUCTOR
:构造方法LOCAL_VARIABLE
:局部变量ANNOTATION_TYPE
:注解类型PACKAGE
:包TYPE_PARAMETER
:类型参数TYPE_USE
:类型用法
2.@Retention
RetentionPolicy
用于@Retention
注解的保留策略:
保留规则 | 描述 |
---|---|
SOURCE | 不包括在类文件中的注解 |
CLASS | 包括在类文件中的注解,但是虚拟机不需要将它们载入 |
RUNTIME | 包括在类文件中的注解,并由虚拟机载入。通过反射API可获得它们 |
3.@Inerited 详解
如果一个类具有继承注解(即被@Inherited
修饰的注解),那么它的所有子类都自动具有相同的注解。
-
假设定义了一个继承注解@Persistent来指定一个类的对象可以存储到数据库中,那么该持久类的子类就会自动被注解为是持久性的。
@Inherited @interface Persistent { } @Persistent class Employee { } class Manager extends Employee { // also @Persistent }
4.@Repeatable 详解
源码:
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
对于Java SE 8来说,将同种类型的注解多次应用于某一项是合法的。为了向后兼容,可重复注解的实现者需要提供一个容器注解,它可以将这些重复注解存储到一个数组中
例子:
@Repeatable(TestRepeatables.class)
public @interface TestRepeatable {
String content() default "请添加描述";
}
数组,用来存储
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestRepeatables {
TestRepeatable[] value();
}
@TestRepeatable(content = "张三")
@TestRepeatable(content = "李四")
@TestRepeatable(content = "王五")
public class Student {
}
@Slf4j
public class StudentTest {
@Test
public void testRepeatable() {
Annotation[] annotations = Student.class.getAnnotations();
for (Annotation annotation : annotations) {
// 输出注解的名称
log.info(annotation.annotationType().getName());
TestRepeatables testRepeatables = (TestRepeatables) annotation;
// 输出注解的内容
for (TestRepeatable a : testRepeatables.value()) {
System.out.println(a.content());
}
}
}
}
2.用于编译的注解
6个基本的注解如下,除了@Generated
位于javax.annotation
包,其它均定义在java.lang
包下:
注解 | 修饰的程序单元 | 作用 |
---|---|---|
@Deprecated | 全部 | 表示某个程序元素(类、方法等)已过时,编译器会发出警告 |
@SuppressWarnings | 除了包和注解之外的所有情况 | 取消显示指定的编译器警告 |
@SafeVarargs | 方法、构造器 | 断言varargs参数可安全使用,抑制堆污染警告 |
@Override | 方法 | 强制一个子类的方法必须是覆盖父类方法的方法 |
@FunctionalInterface | 接口 | 指定某个接口必须是函数式接口 |
@Generated | 全部 | 供代码生成工具来使用,任何生成的源代码都可以被注解,从而与程序员提供的代码区分开 |
3.用于管理资源的注解
注解 | 修饰的程序单元 | 作用 |
---|---|---|
@PostConstruct @PreDestroy | 方法 | 被标记的方法应该在构造之后/移除之前立即被调用 |
@Resource | 类、接口、方法、域 | 在类/接口上:标记为在其他地方要用到的资源 在方法/域上:为“注入”而标记 |
@Resources | 类、接口 | 一个资源数组 |
2.Spring常用注解
基本注解 | 解释 |
---|---|
@Component | 使用在类上,用于实例化Bean 代替xml的标签 |
@Controller | @Component的衍生注解:使用在Web层上,用于实例化Bean |
@Service | @Component的衍生注解:使用在service层类上,用于实例化Bean |
@Repository | @Component的衍生注解:使用在dao层类上,用于实例化Bean |
@Autowired | 通常使用在字段上,用于根据Bean的类型进行依赖注入 |
@Qualifier | 结合@Autowired一起使用用于同时根据类型和名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上,标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上,标注该方法是Bean的销毁方法 |
@Configuration | 用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定Spring在初始化容器时要扫描的包,作用和在Spring的xml配置文件中的<context:component-scan base-package="com.itheima"/> 一样 |
@Bean | 使用在方法上,表示将该方法的返回值存储到Spring容器中,并可赋予指定名称 |
@PropertySource | 用于加载properties文件中的配置 |
@Import | 用于导入其他配置类 |
@AliasFor | 重新声明元注解中的属性 |
1.@Required
The
@Required
annotation andRequiredAnnotationBeanPostProcessor
are formally deprecated as of Spring Framework 5.1./** @deprecated */ @Deprecated @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Required { }
The @Required
annotation applies to bean property setter methods
, as in the following example:
public class SimpleMovieLister {
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// ...
}
This annotation indicates that the affected bean property must be populated at configuration time, through an explicit property value in a bean definition or through autowiring.
2.@Autowired
很多情况下,JSR 330提供的
@Inject
注解可以替换@Autowired
的作用。
@Autowired
根据类型注入Bean,对应类型的Bean需要是单例的。
@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
时,spring会在项目启动的过程中,自动调用一次加了@Autowired
注解的方法,我们可以在该方法做一些初始化的工作
多个Bean类型相同
如果对应的类型有多个,@Autowired
会失败,此时有三种解决方式
-
与
@Qualifier
(合格者、修饰词)结合,在同类型的基础上通过名称再进行取舍; -
在被注入的Bean上加入优先级,如指定某一个Bean为
@Primary
; -
另外,实际上可以将注入的字段改为集合类型:
当集合为Map时,其key必须为String类型,含义为Bean的名字;其value为对应的Bean实例。
@Service public class UserService { @Autowired private List<IUser> userList; @Autowired private Set<IUser> userSet; @Autowired private Map<String, IUser> userMap; public void test() { // userList:[User1@2513a118, User2@2bfb583b] System.out.println("userList:" + userList); // userSet:[User1@2513a118, User2@2bfb583b] System.out.println("userSet:" + userSet); // {user1=User1@2513a118, user2=User2@2bfb583b} System.out.println("userMap:" + userMap); } }
注入Bean集合
@Autowired
注入的字段为集合类型时:
- 集合不能为空,其中必须至少能注入一个Bean,否则Spring将抛异常。
- 如果想控制集合中Bean出现的顺序,可以令相关的Bean实现
Ordered
接口,或通过@Order
、@Priority
注解来定义相对的顺序。 - 如果没有显式的顺序定义,其排列顺序将按照在IoC容器中注册的顺序。
关于required
对于普通方法:
- 如果
@Autowired
修饰的是方法且@Autowired(required = false)
,当Spring发现存在某一个要注入的Bean不存在时,会导致该方法完全不会被执行。
不过,对于构造方法和工厂方法,规则略有不同,因为Spring的构造解析算法需要处理存在多个构造方法的场景:
- 默认情况下,构造方法和工厂方法的参数都是必须存在的;
- 但在只存在单个构造函数的场景中有一些特殊规则,例如,如果没有匹配的bean可用,则会将相应的“多元素注入点”(数组、集合、映射)解析为空对象。
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(Optional<MovieFinder> movieFinder) {
...
}
}
As of Spring Framework 5.0, you can also use a @Nullable
annotation:
public class SimpleMovieLister {
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
...
}
}
注入Spring框架相关Bean
You can also use @Autowired
for interfaces that are well-known resolvable dependencies:
BeanFactory
ApplicationContext
Environment
ResourceLoader
ApplicationEventPublisher
MessageSource
These interfaces and their extended interfaces, such as ConfigurableApplicationContext
or ResourcePatternResolver
, are automatically resolved, with no special setup necessary.
self injection
Note that self injection is a fallback.
自Spring 4.3开始,@Autowired
也支持了“自注入(self injection)”,即注入自己。
Regular dependencies on other components always have precedence:
- In that sense, self references do not participate in regular candidate selection and are therefore in particular never primary.
- On the contrary, they always end up as lowest precedence.
实践中,应该将自注入作为一种最后的不得已的手段(for example, for calling other methods on the same instance through the bean’s transactional proxy),通常更建议将需要用到自注入的方法提取到另外一个委托Bean里。
Alternatively, you can use @Resource
, which may obtain a proxy back to the current bean by its unique name.
通过@Bean
方法来实现自注入也是一种有效的方法。但是,建议要么在实际需要的地方在方法签名中惰性地解析这些引用(与@Autowired
正好相反),要么将受影响的@Bean
方法声明为静态的,从而将它们与母体及其生命周期解耦。否则,此类Bean只会在fallback phase被考虑,而优先考虑其他的符合条件的Bean。
隐式的qualfier
除了直接使用 @Qualifier
注解来修饰Bean外,Spring也支持借助Java的泛型信息来作为一种隐式的修饰语,从而区别不同的Bean。
例如,假设有如下的配置类:
@Configuration
public class MyConfiguration {
@Bean
public StringStore stringStore() {
return new StringStore();
}
@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
假定上述的Bean都实现了一个泛型接口,即Store<String>
和 Store<Integer>
,那么可以直接使用 @Autowire
来注入相应的泛型接口从而注入相应的Bean,即:
@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore beancopyerrorcopiedcopyerrorcopied
该原则也适用于List, Map, array
:
// Inject all Store beans as long as they have an <Integer> generic
// Store<String> beans will not appear in this list
@Autowired
private List<Store<Integer>> s;
失效原因排查
对象未被注入的可能原因:
- 使用
@Autowired
的类不在IoC容器中(没有加@Componet
,@Controller
之类的注解) - 包未被spring扫描
@Autowired
的required = false
.- 在
listener
和filter
里面@Autowired
某个bean:由于web应用启动的顺序是:listener
->filter
->servlet
,而SpringMVC的启动是在DisptachServlet
里面做的,执行在对应的bean还没有初始化,无法自动装配。此时可以通过其他途径来实现。 - 循环依赖问题(在单例情况下多数没问题)
3.@Qualifier
package org.springframework.beans.factory.annotation;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
You can associate qualifier values with specific arguments, narrowing the set of type matches so that a specific bean is chosen for each argument.
In the simplest case, this can be a plain descriptive value, as shown in the following example:
public class MovieRecommender {
@Autowired
@Qualifier("main")
private MovieCatalog movieCatalog;
// ...
}copyerrorcopiedcopyerrorcopied
You can also specify the @Qualifier
annotation on individual constructor arguments or method parameters:
public class MovieRecommender {
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public void prepare(@Qualifier("main") MovieCatalog movieCatalog,
CustomerPreferenceDao customerPreferenceDao) {
this.movieCatalog = movieCatalog;
this.customerPreferenceDao = customerPreferenceDao;
}
// ...
}
注意,尽管Bean的id是唯一的,但
@Qualfier
也始终只是在@Autowired
圈定的范围内进行挑选。Good qualifier values are
main
orEMEA
orpersistent
, expressing characteristics of a specific component that are independent from the beanid
, which may be auto-generated in case of an anonymous bean definition.
@Qualfier
的值不需要是唯一的,因此也可以据此来注入Bean集合。
当需要根据名称来注入Bean时,@Qualfier
并不一定是必需的,因为默认情况下,当有多个候选项时(且没有其他限定条件,如优先级),Spring会根据字段或形参的名称来匹配同名的Bean。
另外,如果就是为了根据修饰性的名称来注入Bean,往往更推荐使用 JSR-250 提供的@Resource
注解,@Resource
本意即是根据唯一的限定名称来注入Bean,不考虑Bean的类型。
4.@Resource
@Resource
takes a name attribute. By default, Spring interprets that value as the bean name to be injected. In other words, it follows by-name semantics
@Autowired是Spring提供的注解,@Resource是Java(JSR-250)提供的注解。
- @Autowired只包含一个参数:required,表示是否开启自动准入,默认是true;而@Resource包含七个参数,其中最重要的两个参数是:name 和 type。
- @Resource只能用在类、成员变量和方法上。
- @Resource的搜索路径:
- 未给定任何参数:首先根据名称匹配(即字段名或setter方法名),如果找不到再根据类型匹配
- 仅指定了name:根据名称装配
- 仅指定了type:根据类型装配
- 同时指定了name和type:寻找名称和类型都匹配的Bean进行装配
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
enum AuthenticationType {
CONTAINER,
APPLICATION
}
}
5.@Order, @Priority, @Primary
这三个注解总的来说都是用来做bean(注入时?)的排序。
-
@Order
是Spring提供的注解,里面存储了一个代表顺序的值,默认为Integer.MAX_VALUE
,值越小优先级越高。@Order
只控制Bean的注入顺序,不影响单例Bean的启动顺序,后者是由依赖关系和@DependsOn
声明决定的。@Order
能控制 List 等有序集合里面存放的Bean的顺序,因为Spring的DefaultListableBeanFactory
类会在注入时调用AnnotationAwareOrderComparator.sort(listA)
,该方法根据@Order
或者Ordered
接口返回的值排序。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) @Documented public @interface Order { int value() default 2147483647; }
-
@Priority
是 JSR 250 标准,与@Order
类似,同样接收一个表示顺序的值,值越小优先级越高。@Priority
优先级比@Order
更高,两者共存时优先加载@Priority
。@Target({TYPE,PARAMETER}) @Retention(RUNTIME) @Documented public @interface Priority { /** * The priority value. */ int value(); }
Note that the standard
@Priority
annotation is not available at the@Bean
level, since it cannot be declared on methods. Its semantics can be modeled through@Order
values in combination with@Primary
on a single bean for each type. -
@Primary
同样是表达顺序的注解,它是Spring提供的注解,其表达的优先级最高的,如果同时有@Primary
以及其他几个的话,@Primary
注解的Bean会优先注入。@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Primary { }
6.@Value
定义
package org.springframework.beans.factory.annotation;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
释义
@Value
is typically used to inject externalized properties:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name}") String catalog) {
this.catalog = catalog;
}
}
With the following configuration:
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig { }
And the following application.properties
file:
catalog.name=MovieCatalog
In that case, the catalog
parameter and field will be equal to the MovieCatalog
value.
Spring提供的内置转换器支持自动处理简单的类型转换(例如Integer或int),同时多个逗号分隔的值可以自动转换为String数组,而无需处理。
设置默认值
@Value也可以设置默认值,如下:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
this.catalog = catalog;
}
}
使用SpEL表达式
When @Value
contains a SpEL
expression the value will be dynamically computed at runtime as the following example shows:
@Component
public class MovieRecommender {
private final String catalog;
public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
this.catalog = catalog;
}
}
7.@AliasFor
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AliasFor {
@AliasFor("attribute")
String value() default "";
@AliasFor("value")
String attribute() default "";
Class<? extends Annotation> annotation() default Annotation.class;
}
@AliasFor
用于声明注解属性的别名,有两种应用场景:
-
同一个注解内的别名
@AliasFor
注解的定义源码本身便是这样一个例子,其属性value
和attribute
互为别名- 也就是说,
@AliasFor(value="xxx")
和@AliasFor(attribute=“xxx”)
是等价的 - 这种用法有几点注意事项:
- 别名属性必须声明相同的返回类型
- 别名属性必须声明默认值且默认值必须相同
-
“继承的”元注解中的属性的别名
-
元注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface BaseAnt { int value(); String home() default ""; }
-
组合注解
@BaseAnt(17) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface CrossAntAliasTester { @AliasFor(value = "home", annotation = BaseAnt.class) // 需声明对应的注解类型 String address(); }
-
@AliasFor
注解在使用时,如果缺省annotation
属性,表示其指向同一个注解中的属性;如果缺省value
属性,则表示指向annotation
字段关联的注解中的同名属性。
8.@Bean
释义
@Bean
is a method-level annotation and a direct analog of the XML <bean/>
element. You can use the @Bean
annotation in a @Configuration
-annotated or in a @Component
-annotated class.
package org.springframework.context.annotation;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
/** @deprecated */
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default "(inferred)";
}
如果没有通过@Bean的name或value属性来设置Bean的名称,默认情况下,@Bean方法定义的Bean的名称就是@Bean方法的名称。如下两者等价:
@Configuration
public class AppConfig {
@Bean
public TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
<beans>
<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>
@Bean
也可以修饰接口的默认方法,从而可以让多个配置类实现同一个接口使得代码得到复用:
public interface BaseConfig {
@Bean
default TransferServiceImpl transferService() {
return new TransferServiceImpl();
}
}
@Configuration
public class AppConfig implements BaseConfig {
}
A @Bean
-annotated method can have an arbitrary number of parameters that describe the dependencies required to build that bean.
@Bean定义Bean的配置信息
使用@Bean
注解,在Spring的组件(Components)中也可以定义Bean的配置信息,就像在@Configureation配置类中所做的那样。例如:
@Component
public class FactoryMethodComponent {
private static int i;
public void doWork() {
// Component method implementation omitted
}
@Bean
@Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
// use of a custom qualifier and autowiring of method parameters
@Bean
protected TestBean protectedInstance(
@Qualifier("public") TestBean spouse,
@Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(spouse);
tb.setCountry(country);
return tb;
}
@Bean
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@Bean
@RequestScope
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
}
@Bean
标识了创建Bean的工厂方法及其他的Bean定义属性信息,例如@Qualifier, @Scope, @Lazy等。
InjectionPoint
自Spring 4.3以后,也可以在工厂方法中声明InjectionPoint
类型的参数,从而可以获取该Bean在创建过程中的Inject Point.
-
Note that this applies only to the actual creation of bean instances, not to the injection of existing instances.
-
As a consequence, this feature makes most sense for beans of prototype scope.
@Component public class FactoryMethodComponent { @Bean @Scope("prototype") public TestBean prototypeInstance(InjectionPoint injectionPoint) { return new TestBean("prototypeInstance for " + injectionPoint.getMember()); } }
Lifecycle callback
@Bean
方法定义的Bean支持正常的生命周期回调,这里不再过多赘述了。
示例:
public class BeanOne {
public void init() {
// initialization logic
}
}
public class BeanTwo {
public void cleanup() {
// destruction logic
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "init")
public BeanOne beanOne() {
return new BeanOne();
}
@Bean(destroyMethod = "cleanup")
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
对于BeanOne
,其等同于如下配置:
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
BeanOne beanOne = new BeanOne();
beanOne.init();
return beanOne;
}
// ...
}
值得一提的是,@Bean
注解的destroyMethod
属性提供了一个默认值"(inferred)"
,如果你不想在IoC容器shutdown的时候执行相应Bean的close或shutdown方法,需要设置destroyMethod=""
。
9.@DependsOn
此注解可以用来调整 Bean 的初始化顺序。比如如果一个BeanB依赖于BeanA的初始化,那么可以给BeanB加上注解@DependsOn("beanA")
,让BeanA先于BeanB初始化。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
String[] value() default {};
}
10.@Conditional
@Conditional
的作用是,在向spring容器中注册组件时,必须判断某个条件满足时才能注册。其定义为:
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
Class<? extends Condition>[] value();
}
如果一个@Configuration
配置类被标识为@Conditional
,意味着该配置类所关联的@Bean
方法、@Import
注解、@ComponentScan
注解都会受限于该@Conditional
的条件。
关于其中的Condition
接口:
package org.springframework.context.annotation;
import org.springframework.core.type.AnnotatedTypeMetadata;
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
Conditions
are checked immediately before the bean-definition is due to be registered and are free to veto registration based on any criteria that can be determined at that point.Conditions
must follow the same restrictions asBeanFactoryPostProcessor
and take care to never interact with bean instances. For more fine-grained control of conditions that interact with@Configuration
beans consider implementing theConfigurationCondition
interface.
3.JSR-330 的注解
Starting with Spring 3.0, Spring offers support for JSR-330 standard annotations (Dependency Injection). To use them, you need to have the relevant jars in your classpath.
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>copyerrorcopiedcopyerrorcopied
When you work with standard annotations, you should know that some significant features are not available, as the following table shows:
Spring | javax.inject.* | javax.inject restrictions / comments |
---|---|---|
@Autowired | @Inject | @Inject has no ‘required’ attribute. Can be used with Java 8’s Optional instead. |
@Component | @Named / @ManagedBean | JSR-330 does not provide a composable model, only a way to identify named components. |
@Scope(“singleton”) | @Singleton | The JSR-330 default scope is like Spring’s prototype . However, in order to keep it consistent with Spring’s general defaults, a JSR-330 bean declared in the Spring container is a singleton by default. In order to use a scope other than singleton , you should use Spring’s @Scope annotation. javax.inject also provides a @Scope annotation. Nevertheless, this one is only intended to be used for creating your own annotations. |
@Qualifier | @Qualifier / @Named | javax.inject.Qualifier is just a meta-annotation for building custom qualifiers. Concrete String qualifiers (like Spring’s @Qualifier with a value) can be associated through javax.inject.Named . |
@Value | - | no equivalent |
@Required | - | no equivalent |
@Lazy | - | no equivalent |
ObjectFactory | Provider | javax.inject.Provider is a direct alternative to Spring’s ObjectFactory , only with a shorter get() method name. It can also be used in combination with Spring’s @Autowired or with non-annotated constructors and setter methods. |