Spring全家桶(七)通过注解配置Bean

Spring是简化j2ee开发的一个框架,通过指定id、类名配置bean虽然简单,但是当bean很多的时候,spring的配置文件会过于臃肿,使用注解技术配置bean使配置更加简介。

一、注解配置bean步骤

注解配置bean的原理是组件扫描,通过在spring配置文件中定义包扫描器,spring就能从classpath下自动扫描、侦测和实例化具有特定注解的bean。

Spring注解有以下四个,位于org.springframework.stereotype目录下。

  1. Component
    基本注解,标识了一个受Spring管理的组件,源码如下:

    package org.springframework.stereotype;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Component {
        String value() default "";
    }
  2. Repository

    标识持久层组件,源码如下:

    package org.springframework.stereotype;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Repository {
        String value() default "";
    }
  3. Service
    标识业务层组件

    package org.springframework.stereotype;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Service {
        String value() default "";
    }
  4. Controller

    标识表现层组件

    package org.springframework.stereotype;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
        String value() default "";
    }

配置bean的步骤:

  1. 在java类中加上Spring标准
  2. 配置文件中扫类所在的包
  3. IOC容器获取bean

Spring有一个默认的bean命名策略:使用非限定类名,第一个字母小写,或者通过value属性设置。举例,一个UserService类,通过Service注解标准了:

package com.stuspring.annbeans.service;

import org.springframework.stereotype.Service;

/** * Created by bee on 17/5/4. */

@Service
public class UserService {
    public void add(){
        System.out.println("UserService add..");
    }
}

在Spring的配置文件中定义组件扫描器(注意引入context命名空间):

<?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-4.3.xsd">

<context:component-scan base-package="com.stuspring.annbeans" />

</beans>

现在Bean已经可以使用了,它的id就是类名UserService首字母小写,即userService。获取bean并调用add方法:

package com.stuspring.annbeans;

import com.stuspring.annbeans.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * Created by bee on 17/5/4. */
public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");

        UserService userService = (UserService) ctx.getBean("userService");
        System.out.println(userService);
        userService.add();
    }
}

打印结果:

com.stuspring.annbeans.service.UserService@c81cdd1
UserService add..

可以通过value属性来设置bean的id,代码如下,这样bean的id就改为uService了。

@Service("uService")
public class UserService {
    public void add(){
        System.out.println("UserService add..");
    }
}

二、组件扫描器中的一些配置

<context:component-scan >可以定义一些属性及配置:

  • base-package属性指定一个需要扫描的基类包,Spring容器将会扫描这个基类包及其子包中的所有类。需要扫描多个包时,可以使用逗号分开。
  • 如果仅需要扫描特定的类而不是基类包下的所有类,可以使用resource-pattern属性过滤特定的类。例如:

    <context:component-scan base-package="com.stuspring.annbeans" resource-pattern="repository/8.class"/>
  • <context:exclude-filter>子节点表示排除在外的目标类

  • <context:include-filter>子节点表示要包含的目标类

三、bean直接的关联关系

在UserController类中创建一个UserService对象:

@Controller
public class UserController {

    private UserService userService;

    public void execute(){
        System.out.println("UserController execute...");
        userService.add();
    }
}

这时候获取UserController对象:

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");

        UserController userController = (UserController) ctx.getBean("userController");
        userController.execute();
    }
}

运行会报空指针异常:

Exception in thread "main" java.lang.NullPointerException
    at com.stuspring.annbeans.controller.UserController.execute(UserController.java:18)
    at com.stuspring.annbeans.Main.main(Main.java:15)
UserController execute...

从打印结果中可以看出UserService在UserController类中没有被标准。<context:component-scan>元素会自动注册AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired、@Resource、@Inject注解的属性。

在UserService对象上添加注解@Autowired:

@Autowired
private UserService userService;

这样UserService对象就会自动装配上。

@Autowired注解会自动装配具有兼容类型的单个Bean属性:

  1. 构造器、普通字段,一切具有参数的方法都可以用@Autowired注解
  2. 默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的Bean装配属性时会抛出异常。若某一属性允许不被设置,可以设置@Autowired注解的required属性为false
  3. 默认情况下, 当IOC容器中存在多个类型兼容的Bean时,通过类型的自动装配将会无法工作,此时可以在@Qualifier注解里提供Bean的名称。Spring允许对方法的入参标注@Qualifier已指定注入的Bean的名称。
  4. @Autowired注解也可以应用在数组类型的属性上,此时Spring会把所有匹配的Bean进行自动装配
  5. @Autowired注解也可以应用在集合属性上,此时Spring读取积累的类型信息,然后自动装配所有与之兼容的Bean。
  6. @Autowired注解用在java.util.map上时,若该map的键值为String,那么Spring将自动装配与之Map类值兼容的Bean,此时Bean的名称作为键值。

你可能感兴趣的:(注解,spring,annotation)