Spring是简化j2ee开发的一个框架,通过指定id、类名配置bean虽然简单,但是当bean很多的时候,spring的配置文件会过于臃肿,使用注解技术配置bean使配置更加简介。
一、注解配置bean步骤
注解配置bean的原理是组件扫描,通过在spring配置文件中定义包扫描器,spring就能从classpath下自动扫描、侦测和实例化具有特定注解的bean。
Spring注解有以下四个,位于org.springframework.stereotype
目录下。
- 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 "";
}
- 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 "";
}
- 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 "";
}
- 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的步骤:
- 在java类中加上Spring标准
- 配置文件中扫类所在的包
- 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属性:
- 构造器、普通字段,一切具有参数的方法都可以用@Autowired注解
- 默认情况下,所有使用@Autowired注解的属性都需要被设置。当Spring找不到匹配的Bean装配属性时会抛出异常。若某一属性允许不被设置,可以设置@Autowired注解的required属性为false
- 默认情况下, 当IOC容器中存在多个类型兼容的Bean时,通过类型的自动装配将会无法工作,此时可以在@Qualifier注解里提供Bean的名称。Spring允许对方法的入参标注@Qualifier已指定注入的Bean的名称。
- @Autowired注解也可以应用在数组类型的属性上,此时Spring会把所有匹配的Bean进行自动装配
- @Autowired注解也可以应用在集合属性上,此时Spring读取积累的类型信息,然后自动装配所有与之兼容的Bean。
- @Autowired注解用在java.util.map上时,若该map的键值为String,那么Spring将自动装配与之Map类值兼容的Bean,此时Bean的名称作为键值。