全栈工程师JavaEE 学习专题程序员

spring注解学习

2017-06-30  本文已影响194人  Dl_毛良伟

采用注解的优势:

以前配置bean的方法及在bean之间建立依赖关系的做法

以用户购买商品为例主要有四个实体类(items,orderdateil,user)
商品信息 Items.java

public class Items {
    private Integer id;
    private String name;
    private Float price;
    private String pic;
    private Date createtime;
    private String detail;

//省略 get/setter

   @Override
    public String toString() {
        return "Items{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", pic='" + pic + '\'' +
                ", createtime=" + createtime +
                ", detail='" + detail + '\'' +
                '}';
    }
}

订单明细(包含用户信息与商品信息) Orderdetail.java

public class Orderdetail {
    private int id;
    private Items items;
    private User user;

//省略get/setter方法
    @Override
    public String toString() {
        return "Orderdetail{" +
                "id=" + id +
                ", items=" + items +
                ", user=" + user +
                '}';
    } 
}

用户 User.jav

public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
//省略get/setter方法
 @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", iId=" + iId +
                '}';
    }
}

在spring容器中我们将User和Order两个类声明为bean,并注入到Orderdetail这个bean中,因此创建一个bean.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
       http://www.springframework.org/schema/mvc">

    <bean id="items" class="pojo.Items">
        <property name="name" value="苹果手机"></property>
        <property name="price" value="10000"></property>
    </bean>
    <bean id="user" class="pojo.User">
        <property name="username" value="张三"></property>
        <property name="address" value="陝西西安"></property>
    </bean>
    <bean id="orderdetail" class="pojo.Orderdetail">
        <property name="items" ref="items"></property>
        <property name="user" ref="user"></property>
    </bean>

</beans>

测试 Test.java (输出订单明细时,成功时就会打印用户与商品的相关信息)

package test;

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

/**
 * Created by admin on 2017/6/30.
 */
public class Test {
    public static void main(String[] args) {
        String path = "bean.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
        Orderdetail orderdetail = (Orderdetail) applicationContext.getBean("orderdetail");
        System.out.println(orderdetail);
    }
}

图片.png

使用 @Autowired 注释

使用@Autowired注释Orderdetail
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="items" class="pojo.Items" scope="singleton">
        <property name="name" value="三星手机"></property>
        <property name="price" value="10000"></property>
    </bean>
    <bean id="user" class="pojo.User">
        <property name="username" value="李四"></property>
        <property name="address" value="陝西西安"></property>
    </bean>
    <!-- 移除 boss Orderdetail 的属性注入配置的信息 -->
    <bean id="orderdetail" class="pojo.Orderdetail">
    </bean>

    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>
</beans>

Orderdetail.java

package pojo;

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

public class Orderdetail {
    private int id;
    @Autowired
    private Items items;
    @Autowired
    private User user;


    @Override
    public String toString() {
        return "Orderdetail{" +
                "id=" + id +
                ", items=" + items +
                ", user=" + user +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

用测试类测试:

图片.png

在 beans.xml 中配置两个 User类型的 Bean时

    <bean id="user" class="pojo.User">
        <property name="username" value="李四"></property>
        <property name="address" value="陝西西安"></property>
    </bean>
    <bean id="user1" class="pojo.User">
        <property name="username" value="张三"></property>
        <property name="address" value="陝西西安"></property>
    </bean>

这样配置时,就会发生异常,因为Spring 容器将无法确定到底要用哪一个 Bean,Spring 允许我们通过 @Qualifier 注释指定注入 Bean 的名称,这样歧义就消除了。

    @Autowired
    @Qualifier("user")
    private User user;

使用 @Resource 注释

@Resource 的作用相当于 @Autowired,只不过 @Autowired 按 byType 自动注入,面@Resource 默认按 byName 自动注入罢了。@Resource 有两个属性是比较重要的,分别是 name 和 type,Spring 将@Resource 注释的 name 属性解析为 Bean 的名字,而 type 属性则解析为 Bean 的类型。所以如果使用 name 属性,则使用 byName 的自动注入策略,而使用 type 属性时则使用 byType 自动注入策略。如果既不指定 name 也不指定 type 属性,这时将通过反射机制使用 byName 自动注入策略。

    // 自动注入类型为 Items 的 Bean
    @Resource
    private Items items;
    // 自动注入 bean 名称为 user 的 Bean
    @Resource(name = "user")
    private User user;

使用 <context:annotation-config/> 简化配置

Spring 2.1 添加了一个新的 context 的 Schema 命名空间,该命名空间对注释驱动、属性文件引入、加载期织入等功能提供了便捷的配置。我们知道注释本身是不会做任何事情的,它仅提供元数据信息。要使元数据信息真正起作用,必须让负责处理这些元数据的处理器工作起来。

而我们前面所介绍的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是处理这些注释元数据的处理器。但是直接在 Spring 配置文件中定义这些 Bean 显得比较笨拙。Spring 为我们提供了一种方便的注册这些BeanPostProcessor 的方式,这就是 <context:annotation-config/>。

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

    <context:annotation-config/>
    
    <bean id="items" class="pojo.Items" scope="singleton">
        <property name="name" value="三星手机"></property>
        <property name="price" value="10000"></property>
    </bean>
    <bean id="user" class="pojo.User">
        <property name="username" value="李四"></property>
        <property name="address" value="陝西西安"></property>
    </bean>
    <bean id="user1" class="pojo.User">
        <property name="username" value="张三"></property>
        <property name="address" value="陝西西安"></property>
    </bean>
    <!-- 移除 boss Orderdetail 的属性注入配置的信息 -->
    <bean id="orderdetail" class="pojo.Orderdetail">
    </bean>

<!--    <!–@Autowired–>
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"></bean>
    <!–@Resource–>
    <bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>-->
</beans>

<context:annotationconfig/> 将隐式地向 Spring 容器注册 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor 以及equiredAnnotationBeanPostProcessor 这 4 个 BeanPostProcessor。

在配置文件中使用 context 命名空间之前,必须在 <beans> 元素中声明 context 命名空间。

使用 @Component

虽然我们可以通过 @Autowired 或 @Resource 在 Bean 类中使用自动注入功能,但是 Bean 还是在 XML 文件中通过 <bean> 进行定义 —— 也就是说,在 XML 配置文件中定义 Bean,通过@Autowired 或 @Resource 为 Bean 的成员变量、方法入参或构造函数入参提供自动注入的功能。能否也通过注释定义 Bean,从 XML 配置文件中完全移除 Bean 定义的配置呢?答案是肯定的,我们通过 Spring 2.5 提供的@Component 注释就可以达到这个目标了。

为什么 @Repository 只能标注在 DAO 类上呢?这是因为该注解的作用不只是将类识别为 Bean,同时它还能将所标注的类中抛出的数据访问异常封装为 Spring 的数据访问异常类型。 Spring 本身提供了一个丰富的并且是与具体的数据访问技术无关的数据访问异常结构,用于封装不同的持久层框架抛出的异常,使得异常独立于底层的框架。

Spring 2.5 在 @Repository 的基础上增加了功能类似的额外三个注解:@Component、@Service、@Constroller,它们分别用于软件系统的不同层次:

@Component 是一个泛化的概念,仅仅表示一个组件 (Bean) ,可以作用在任何层次。
@Service 通常作用在业务层,但是目前该功能与 @Component 相同。
@Constroller 通常作用在控制层,但是目前该功能与 @Component 相同。

通过在类上使用 @Repository、@Component、@Service 和 @Constroller 注解,Spring 会自动创建相应的 BeanDefinition 对象,并注册到 ApplicationContext 中。这些类就成了 Spring 受管组件。这三个注解除了作用于不同软件层次的类,其使用方式与 @Repository 是完全相同的。

接下来完全使用注释定义 Bean 并完成 Bean 之间装配:

Items .java

package pojo;

import org.springframework.stereotype.Component;

import java.util.Date;

@Component  //使用 @Component 注释就可以将一个类定义为 Spring 容器中的 Bean
public class Items {
    private Integer id;
    private String name;
    private Float price;
    private String pic;
    private Date createtime;
    private String detail;
    @Override
    public String toString() {
        return "Items{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", pic='" + pic + '\'' +
                ", createtime=" + createtime +
                ", detail='" + detail + '\'' +
                '}';
    }

//省略get/set方法
}

User.java

@Component
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                ", iId=" + iId +
                '}';
    }

Orderdetail.java

package pojo;

import javax.annotation.Resource;

public class Orderdetail {
    private int id;
    // 自动注入类型为 Items 的 Bean
    @Resource
    private Items items;
    // 自动注入 bean 名称为 user 的 Bean
    @Resource(name = "user")
    private User user;


    @Override
    public String toString() {
        return "Orderdetail{" +
                "id=" + id +
                ", items=" + items +
                ", user=" + user +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

升级之后的配置文件beanUp.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-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="pojo"/>
</beans>

这里,所有通过 <bean> 元素定义 Bean 的配置内容已经被移除,仅需要添加一行 <context:component-scan/> 配置就解决所有问题了——Spring XML 配置文件得到了极致的简化(当然配置元数据还是需要的,只不过以注释形式存在罢了)。<context:component-scan/> 的 base-package 属性指定了需要扫描的类包,类包及其递归子包中所有的类都会被处理。

上一篇 下一篇

猜你喜欢

热点阅读