从Spring2.5可以使用基于注解的依赖注入。因此可以替代XML去描述bean的包装,你可以在组建类上使用注解在相关的类,方法或域声明上。
注解的注入在XML注入之前执行,然而后者的配置将覆盖前者的包装属性通过两种方式。
基于注解的包装Spring容器不是默认打开的。因此,在你可以使用注解包装之前,你需要在Spring配置文件中开启它。因此考虑如下的配置文件如果你想使用任何注解在Spring应用中。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- bean definitions go here -->
</beans>
一旦<context:annotation-config/>配置了,你可以开始注解你的代码指明Spring将会自动的包装值到属性、方法、构造函数。让我们看看几个重要的注解去理解他们如何工作的:
序号 | 注解&描述 |
1 | @Required @Required注解使用在bean的属性setter方法上。 |
2 | @Autowired @Autowired注解可以使用在bean属性setter方法、非setter方法、构造函数、属性上。 |
3 | @Qualifier Qualifier注解总是跟着@Autowired可以消除装配的混乱通过指明确切的bean来装配。 |
4 | JSR-250 Annotations Spring支持基于JSR-250标准的注解包括@Resource,@PostConstruct和@PreDestroy注解。 |
Spring @Required注解
@Required注解应用于bean的属性setter方法并且它指明影响的bean属性必须陪hi在XML配置文件中否则容器会抛出BeanInitializationException异常。如下展示了@Required注解的用法。
示例
让我们使用Eclipse IDE按如下的步骤创建一个Spring应用:
步骤 | 描述 |
1 | 创建一个SpringExample的项目并在src目录下创建com.tutorialspoint包。 |
2 | 在Add External JARs选项卡中添加Spring库如在Spring Hello World章节中所讲。 |
3 | 在com.tutorialspoint包下创建Student、 MainApp类。 |
4 | 在src目录下创建bean的配置文件Beans.xml |
5 | 最后一步在Java类中和Bean配置文件中添加内容,并运行应用。 |
如下是Student的源代码:
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Required;
public class Student {
private Integer age;
private String name;
@Required
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
如下是MainApp的源代码:
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Student student = (Student) context.getBean("student");
System.out.println("Name : " + student.getName());
System.out.println("Age : " + student.getAge());
}
}
如下是配置文件Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for student bean -->
<bean id="student" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<!-- try without passing age and check the result -->
<!-- property name="age" value="11" -->
</bean>
</beans>
一但你创建成功源代码和配置文件,运行应用。如果一切正常,这将会抛出BeanInitializationException异常并且打印如下异常和其他log信息:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'student' defined in class path resource[Beans15.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanInitializationException: Property 'age' is required for bean 'student'
……………
接下来,你可以移除例子中注释掉的“age”属性如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for student bean -->
<bean id="student" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<property name="age" value="11" />
</bean>
</beans>
现在上面的例子将会输出如下结果:
Name : Zara
Age : 11
Spring @Autowired注解
@Autowired注解提供了更细粒度的控制在何处和如何自动完成装配上。@Autowired注解可以使用在自动装配bean的setter方法上就像@Required注解、构造函数、属性、和任意名字或多参数的方法上。
@Autowired在setter方法上
你可以使用@Autowired注解在setter方法上去摆脱<property>元素在XML配置文件中。当Spring发现@Autowired注解使用在setter方法上时,它会尝试在方法上根据类型自动包装。
示例
让我们使用Eclipse IDE按如下的步骤创建一个Spring应用:
步骤 | 描述 |
1 | 创建一个SpringExample的项目并在src目录下创建com.tutorialspoint包。 |
2 | 在Add External JARs选项卡中添加Spring库如在Spring Hello World章节中所讲。 |
3 | 在com.tutorialspoint包下创建TextEditor、SpellChecker 、 MainApp类。 |
4 | 在src目录下创建bean的配置文件Beans.xml |
5 | 最后一步在Java类中和Bean配置文件中添加内容,并运行应用。 |
如下是TextEditor源代码:
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
private SpellChecker spellChecker;
@Autowired
public void setSpellChecker(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
如下是依赖类SpellChecker的源代码:
package com.tutorialspoint;
public class SpellChecker {
public SpellChecker() {
System.out.println("Inside SpellChecker constructor.");
}
public void checkSpelling() {
System.out.println("Inside checkSpelling.");
}
}
如下是MainApp的源代码:
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
TextEditor te = (TextEditor) context.getBean("textEditor");
te.spellCheck();
}
}
如下是配置文件Beans.xml:
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for textEditor bean withoutconstructor-arg -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
</bean>
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
</beans>
一旦你完成了上面源代码和配置文件,运行应用,如果一切正常,会打印如下消息:
Inside SpellChecker constructor.
Inside checkSpelling.
@Autowired在属性上
你可以使用@Autowired注解在属性上去摆脱setter方法。当你使用<property>标签传递自动装配的值时,Spring将会自动的指派传递的值或引用给属性。因此是哦那个@Autowired在属性上,你的TextEditor源代码将会是下面这个样子:package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class TextEditor {
@Autowired
private SpellChecker spellChecker;
public void setSpellChecker(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
如下是配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for textEditor bean -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
</bean>
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
</beans>
一旦你完成了上面源代码和配置文件,运行应用,如果一切正常,会打印如下消息:
Inside SpellChecker constructor.
Inside checkSpelling.
构造函数使用@Autowired
你也可以使用@Autowired到构造函数。@Autowired使用在构造函数上表明构造函数将会自动包装当创建bean时,尽管配置文件没有使用<constructor-arg>元素。让我们检查一下下面的例子。
如下是TextEditor的源代码:
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public classTextEditor {
privateSpellChecker spellChecker;
@Autowired
publicTextEditor(SpellChecker spellChecker) {
System.out.println("Inside TextEditor constructor.");
this.spellChecker = spellChecker;
}
publicvoidspellCheck() {
spellChecker.checkSpelling();
}
}
如下是Bean配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for textEditor bean without constructor-arg -->
<bean id="textEditor" class="com.tutorialspoint.TextEditor">
</bean>
<!-- Definition for spellChecker bean -->
<bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
</bean>
</beans>
一旦你完成了上面源代码和配置文件,运行应用,如果一切正常,会打印如下消息:
Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.
@Autowired带有选项(required=false)
默认,@Autowired注解意味着依赖是必须的类是@Required注解,然而,你可以关闭这个默认的行为通过使用@Autowired的(required=false)选项。
这个例子将会工作尽管你没有传递任何值给age属性,但name属性是必须的。你可以试着练习这个例子,它和@Required注解实例类似,只是更改了Student类。
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
private Integer age;
private String name;
@Autowired(required = false)
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Autowired
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Spring @Qualifier注解
或许有一种情况,同一个类型你可以创建多个bean对象,只想使用一个包装属性,这种情况你可以使用@Qualifier注解跟着@Autowired注解,通过指明确定的包装bean消除混乱。如下例子展示了@Qualifier注解。
示例
让我们使用Eclipse IDE按如下的步骤创建一个Spring应用:
描述 | |
1 | 创建一个SpringExample的项目并在src目录下创建com.tutorialspoint包。 |
2 | 在Add External JARs选项卡中添加Spring库如在Spring Hello World章节中所讲。 |
3 | 在com.tutorialspoint包下创建Student、 Profile、 MainApp类。 |
4 | 在src目录下创建bean的配置文件Beans.xml |
5 | 最后一步在Java类中和Bean配置文件中添加内容,并运行应用。 |
如下是Student的源代码:
package com.tutorialspoint;
public class Student {
private Integer age;
private String name;
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
如下是Profile的源代码:
package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
@Autowired
@Qualifier("student1")
private Student student;
public Profile() {
System.out.println("Inside Profile constructor.");
}
public void printAge() {
System.out.println("Age : " + student.getAge());
}
public void printName() {
System.out.println("Name : " + student.getName());
}
}
如下是MainApp的源代码:
package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
Profile profile = (Profile) context.getBean("profile");
profile.printAge();
profile.printName();
}
}
考虑示例如下的配置文件Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<!-- Definition for profile bean -->
<bean id="profile" class="com.tutorialspoint.Profile">
</bean>
</bean>
<!-- Definition for student1 bean -->
<bean id="student1" class="com.tutorialspoint.Student">
<property name="name" value="Zara" />
<property name="age" value="11" />
</bean>
<!-- Definition for student2 bean -->
<bean id="student2" class="com.tutorialspoint.Student">
<property name="name" value="Nuha" />
<property name="age" value="2" />
</bean>
</beans>
一旦你完成了上面源代码和配置文件,运行应用,如果一切正常,会打印如下消息:
Inside Profile constructor.
Age : 11
Name : Zara
Spring JSR-250注解
基于JSR-250的注解包括@PostConstructor、@PreDestroy、@Resource。尽管这些注解不是一定需要的因为你有其他的替代但还是让我简单讲述一下他们。
@PostConstruct 和 @PreDestroy注解
定义装配和卸载一个bean,我们简单的通过声明bean带有<init-method>和<destroy-method>参数。这个init-method属性指明这个方法必须在bean实例化后立即调用。相同,destroy-method指明容器在销毁这个bean之前调用这个方法。
你可以使用@PostConstruct注解作为可选的初始化回调,@PreDestroy注解作为可选的销毁回调方法,如下示例解释。
示例
让我们使用Eclipse IDE按如下的步骤创建一个Spring应用:
步骤 | 描述 |
1 | 创建一个SpringExample的项目并在src目录下创建com.tutorialspoint包。 |
2 | 在Add External JARs选项卡中添加Spring库如在Spring Hello World章节中所讲。 |
3 | 在com.tutorialspoint包下创建HelloWorld 、 MainApp类。 |
4 | 在src目录下创建bean的配置文件Beans.xml |
5 | 最后一步在Java类中和Bean配置文件中添加内容,并运行应用。 |
如下是HelloWorld源代码:
package com.tutorialspoint;
import javax.annotation.*;
public class HelloWorld {
private String message;
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
System.out.println("Your Message : " + message);
return message;
}
@PostConstruct
public void init() {
System.out.println("Bean is going through init.");
}
@PreDestroy
public void destroy() {
System.out.println("Bean will destroy now.");
}
}
如下是MainApp的源文件,这里你需要注册一个关闭的钩子registerShutdownHook()方法这个方法在AbstractApplicationContext类中声明。这将确保完美的关闭和调用销毁相关的方法。
package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApper5veree {
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans15.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
context.registerShutdownHook();
}
}
如下是需要init和destroy方法的配置文件Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld"
init-method="init" destroy-method="destroy">
<property name="message" value="Hello World!" />
</bean>
</beans>
一旦你完成了上面源代码和配置文件,运行应用,如果一切正常,会打印如下消息:
Bean is going through init.
Your Message : Hello World!
Bean will destroy now.
@Resource注解
你可以使用@Resource注解在域上或setter方法上,它同样可以在Java EE 5下工作。@Resource注解带有“name”属性,它将会解释相同名字的bean注入。你可以说,它和根据名字装配的语义相同,如下所示。示例
package com.tutorialspoint;
import javax.annotation.Resource;
public class TextEditor {
private SpellChecker spellChecker;
@Resource(name = "spellChecker")
public void setSpellChecker(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
public SpellChecker getSpellChecker() {
return spellChecker;
}
public void spellCheck() {
spellChecker.checkSpelling();
}
}
如果没有“name”被精确的指明,这个默认的名字是从域名或setter方法推断得来。如果是域,它就是域名;如果是setter方法,它就是bean的属性名。