Spring - 基于配置的注解

22 篇文章 0 订阅

基于配置的注解
从Spring 2.5开始可以使用注解来配置依赖注入,所以你可以在组件类、方法以及域的声明中使用注解来替代XML的配置说明。

如果注解和XML都配置了依赖注入,那么注解会覆盖XML中的属性配置的依赖注入。

在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/>被配置,你就可以在组件类、方法以及构造中使用注解注入。下面看下几个重要的注解注入:

NoAnnotationDescription
1@Required该注解应用到bean属性的setter方法中
2@Autowired该注解可以在bean属性的setter方法、非setter方法、构造以及其属性中
3@Qualifier该注解和@Autowired一起使用,为了确定哪一个bean是要被注入的
4JSP-250AnnotationsSpring支持JSR-250的注解,其中包含@Resource, @PostConstruct和 @PreDestroy

Spring @Required Annotation

@Required 注解适用于bean属性的setter方法,预示着受影响的bean必须在XML配置文件中配置。否则,容器会抛出BeanInitializationException异常,下面的例子将说明该问题

Example

Student.java

package com.soygrow.RequireAnnotation;

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.java

package com.soygrow.RequireAnnotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("RequiredBeans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println("Name : " + student.getName());
        System.out.println("Age : " + student.getAge());
    }
}

RequiredBeans.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <bean id="student" class="com.soygrow.RequireAnnotation.Student">
        <property name="name" value="Zara" />
        <property name="age" value="11"/>
    </bean>
</beans>

如果一切正常,运行结果如下所示:

Name : Zara
Age : 11

如果在XML中不加一下代码,会抛出BeanInitializationException异常

<property name="age" value="11"/>
BeanInitializationException: Property 'age' is required for bean 'student'
小结
  • @Required是作用于setter方法
  • 一旦使用@Required,那么容器在初始化bean的时候必须要进行set
  • @Required注解表示受影响的bean属性必须在XML配置文件中进行配置填充,不然会抛异常
  • Spring使用@Required注解依赖检查

Spring @Autowired Annotation

@Autowired 注解提供了更细微的控制,关于在哪里以及如何完成自动装配。@Autowired 可以在setter方法上自动装配bean,就像@Required注解、构造函数、具有任意名称或者多个参数的属性或方法一样。

@Autowired on Setter Methods

你可以在setter方法中使用@Autowired注解来消除XML配置文件中的属性。当Spring发现一个@Autowired注解在setter方法中使用,那么它会尝试autowired = byType的方式进行依赖注入。

Example

SpellChecker.java

package com.soygrow.AutowiredAnnotation;

public class SpellChecker {
    public SpellChecker() {
        System.out.println("Inside SpellChecker constructor ...");
    }
    public void checkSpelling() {
        System.out.println("Inside checkSpelling ...");
    }
}

TextEditor.java

package com.soygrow.AutowiredAnnotation;

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();
    }
}

MainApp.java

package com.soygrow.AutowiredAnnotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("AutowiredBeans.xml");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

AutowiredBeans.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <bean id="textEditor" class="com.soygrow.AutowiredAnnotation.TextEditor">

    </bean>

    <bean id="spellChecker" class="com.soygrow.AutowiredAnnotation.SpellChecker">

    </bean>
</beans>

如果一切正常,运行的结果如下:

Inside SpellChecker constructor ...
Inside checkSpelling ...

小结:
- @Autowired 作用在setter方法上,可以免去XML配置中的<property>,Spring容器会自动根据type进行依赖注入

@Autowired on Properties

@Autowired 在setter方法上使用,可以消除XML配置中的<property>属性,进一步的在成员变量上使用,可以消除setter方法。当你使用<property>属性去自动装配属性值的时候,Spring容器会自动分配传递的值或者引用的值给autowired的属性。

因此使用@Autowired的TextEditor.java的文件将会像下面这样:

package com.soygrow.AutowiredAnnotation2;

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

public class TextEditor {
    @Autowired
    private SpellChecker spellChecker;

    public TextEditor() {
        System.out.println("Inside TextEditor constructor ..." );
    }

    public SpellChecker getSpellChecker() {
        return spellChecker;
    }

    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}

SpellChecker.java的代码是差不多的,这里就不贴代码了,可以参照以前的代码。

MainApp.java

package com.soygrow.AutowiredAnnotation2;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("AutowiredBeans2.xml");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

AutowiredBeans2.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <bean id="textEditor" class="com.soygrow.AutowiredAnnotation2.TextEditor">

    </bean>

    <bean id="spellChecker" class="com.soygrow.AutowiredAnnotation2.SpellChecker">

    </bean>
</beans>

如果一切正常,运行的结果是:

Inside TextEditor constructor ...
Inside SpellChecker constructor ...
Inside checkSpelling ...
小结
  • 进一步@Autowired在类的成员变量上使用,可以进一步消除类中setter方法,不仅仅是XML配置文件中的<property>

@Autowired on Constructors

同样你可以在构造方法中应用@Autowired,构造方法的@Autowired注解表明党创建bean的时候就自动装配构造方法,甚至在XML配置文件中如果没有<constructor-arg>元素也是可以行的。下面是相应的示例:

Example

TextEditor.java

package com.soygrow.AutowiredAnnotation3;

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

public class TextEditor {
    private SpellChecker spellChecker;

    @Autowired
    public TextEditor(SpellChecker spellChecker) {
        System.out.println("Inside TextEditor constructor ..." );
        this.spellChecker = spellChecker;
    }

    public void spellCheck() {
        spellChecker.checkSpelling();
    }
}

MainApp.java

package com.soygrow.AutowiredAnnotation3;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("AutowiredBeans3.xml");
        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

AutowiredBeans3.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>
    <bean id="textEditor" class="com.soygrow.AutowiredAnnotation3.TextEditor">
    </bean>

    <bean id="spellChecker" class="com.soygrow.AutowiredAnnotation3.SpellChecker">
    </bean>
</beans>

如果一切正常,运行结果:

Inside TextEditor constructor ...
Inside SpellChecker constructor ...
Inside checkSpelling ...
小结
  • @Autowired 注解构造函数,Spring 容器会自动将bean作为参数注入到对应的地方

@Autowired with (required=false) option

By default, the @Autowired annotation implies the dependency is required similar to @Required annotation, however, you can turn off the default behavior by using the (required=false) option with @Autowired.
默认情况下,@Autowired 注解实现依赖注入和 @Required 相类似,然而,你可以是用使用 required=false 取消@Autowired的默认设置。

The following example will work even if you do not pass any value for age property but still it will demand for the name property. You can try this example yourself because this is similar to the @Required annotation example except that only Student.java file has been changed.
下面的例子在你不传age值的情况下,仍然可以正常工作,但是它仍然需要name属性。你可以尝试下面的例子,和上面例子对比,只有下面的文件发生了变化:

Student.java

package com.soygrow.AutowiredAnnotation;

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;
    }
}

总结

  • @Autowired 注解setter方法,免去在XML中配置<property>属性,如果在Autowired中添加(required=false),那么该参数在没有配置的情况也是可以正确执行的,表示该参数不是必须参数。这个和@Required正好相反,@Required表示参数是必须参数
  • @Autowired 注解对象,不仅仅免去XML中的<property>属性配置,也省去了setter方法
  • @Autowired 注解构造方法,Spring 容器会自动找到对应的对象进行注入。

Spring @Qualifier Annotation

存在一种场景,你可以创建同种类型的bean多个,但是你只想绑定其中的一个。再这种场景下,你可以使用@Qualifier注解去解除歧义,使用确切的bean进行装配。下面的例子将说明这个问题:

Example

Student.java

package com.soygrow.QualifierAnnotation;

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.java

package com.soygrow.QualifierAnnotation;

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.java

package com.soygrow.QualifierAnnotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("QualifierBeans.xml");

        Profile profile = (Profile) context.getBean("profile");
        profile.printAge();
        profile.printName();
    }
}

QualifierBeans.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config></context:annotation-config>

    <bean id="profile" class="com.soygrow.QualifierAnnotation.Profile"></bean>
    <bean id="student1" class="com.soygrow.QualifierAnnotation.Student">
        <property name="age" value="11"/>
        <property name="name" value="Zara"/>
    </bean>

    <bean id="student2" class="com.soygrow.QualifierAnnotation.Student">
        <property name="name" value="Nuha"/>
        <property name="age" value="2"/>
    </bean>
</beans>

如果一切正常,运行的结果:

Inside Profile constructor ...
Age : 11
Name : + Zara
总结
  • @Qualifier 可以指定确切的bean对象进行注入,通过名称来区分
  • 和@Autowired 一起使用

Spring JSR-250 Annotations

Spring 也支持JSR-250注解,其中包含@PostConstruct@PreDestroy@Resource注解。虽然这些注解你不是真的需要,因为你又其他替代选择,可以作为了解的知识。

@PostConstruct and @PreDestroy Annotations

定义一个bean的setup和teardown,我们可以使用<bean>init-methoddestroy-method参数来指定。init-method指定了一个方法,该方法会在bean初始化的时候被调用,同样destroy-method指定了bean在销毁时回调的方法。

你可以使用@PostConstruct注解作为初始化回调方法的替代,使用@PreDestroy注解作为销毁回调方法的替代。

Example

HelloWorld.java

package com.soygrow.JSR250Annotation;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class HelloWorld {
    private String message;

    public void setMessage(String message) {
        this.message = message;
    }

    public String getMessage() {
        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.java

package com.soygrow.JSR250Annotation;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("Jsr250Beans.xml");

        HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
        obj.getMessage();
        context.registerShutdownHook();
    }
}

Jsr250Beans.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config></context:annotation-config>

    <bean id="helloWorld" class="com.soygrow.JSR250Annotation.HelloWorld">
        <property name="message" value="Hello World!"/>
    </bean>
</beans>

如果一切正常,运行的结果是:

Bean is going through init ...
Bean will destroy now ...
小结
  • @PostConstruct 可以作为XML中 init-method 的替代
  • @ProDestroy 可以作为XML中 destroy-method 的替代

@Resource Annotation

你可以使用@Resource注解在某个域或者setter方法上,并且它和在Java EE 5 中作用一样(之前不是搞java的,没有明白)。@Resource 带一个‘name’属性,这个name指明一个注入的bean。下面的例子可以说明该问题:

Example

SpellChecker.java

package com.soygrow.ResourceAnnotation;

public class SpellChecker {
    public SpellChecker(){
        System.out.println("Inside SpellChecker constructor." );
    }
    public void checkSpelling(){
        System.out.println("Inside checkSpelling." );
    }
}

TextEditor.java

package com.soygrow.ResourceAnnotation;

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();
    }
}

MainApp.java

package com.soygrow.ResourceAnnotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("ResourceBeans.xml");

        TextEditor te = (TextEditor) context.getBean("textEditor");
        te.spellCheck();
    }
}

ResourceBeans.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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config></context:annotation-config>
    <bean id="textEditor" class="com.soygrow.ResourceAnnotation.TextEditor">

    </bean>
    <bean id="spellChecker" class="com.soygrow.ResourceAnnotation.SpellChecker"></bean>
</beans>

如果一切正常,运行结果:

Inside SpellChecker constructor.
Inside checkSpelling.
小结
  • @Resource 通过名称实现依赖注入,可以指定具体的bean
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值