組件裝配:
<context:component-sacan> 元素還會自動注冊 AutowiredAnnotationBeanPostProcesser 實例 , 該實例可以自動裝配具有 @Autowired 和 @Resource 、 @Inject 注解的屬性。
使用 @Autowired 自動裝配 Bean:
@Autowired 注解自動裝配具有兼容類型的單個 Bean 屬性:
- 構造器 , 普通字段(即使是非 public) , 一切具有參數的方法都可以用 @Autowired 注解。
- 默認情況下 , 所有使用 @Autowired 注解的屬性都需要被設置。當 Spring 找不到匹配的 bean 裝配屬性時 , 會拋出異常 , 若某一屬性允許不被設置 , 可以設置 @Autowired 注解的 required 屬性為 false。
- 默認情況下 , 當 IOC 容器里存在多個類型兼容的 bean 時 , 通過類型的自動裝配將無法工作 , 此時可以在 @Qualifier 注解里提供 bean 的名稱。Spring 允許對方法的入參標注 @Qualifiter 已指定注入 bean 的名稱。或在需要自動裝配的注解中通過 value 屬性值標識組件的名稱。
- @Autowired 注解也可以應用在數組類型的屬性上 , 此時 Spring 將會把所有匹配的 bean 進行自動裝配。
- @Autowired 注解也可以應用在集合屬性上 , 此時 Spring 讀取該集合的類型信息 , 然后自動裝配所有與之兼容的 bean。
- @Autowired 注解用在 java.util.Map 上時 , 若該 Map 的鍵值為 String , 那么 Spring 將自動裝配與之 Map 值類型兼容的 bean , 此時 bean 的名稱作為鍵值。
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:context="http://www.springframework.org/schema/context"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
7
8 <!-- 指定 Spring IOC 容器掃描的包 -->
9 <context:component-scan base-package="com.itdjx.spring.annotation"/>
10
11 </beans>
1 package com.itdjx.spring.annotation.controller;
2
3 import com.itdjx.spring.annotation.service.UserService;
4 import org.springframework.stereotype.Controller;
5
6 /**
7 * @author Wáng Chéng Dá
8 * @create 2017-03-03 9:28
9 */
10 @Controller
11 public class UserController {
12 private UserService userService;
13
14 public void execute() {
15 System.out.println("I am UserController's execute method...");
16 userService.add();
17 }
18 }
1 package com.itdjx.spring.annotation.service;
2
3 import com.itdjx.spring.annotation.repository.UserRepository;
4 import org.springframework.stereotype.Service;
5
6 /**
7 * @author Wáng Chéng Dá
8 * @create 2017-03-03 9:26
9 */
10 @Service
11 public class UserService {
12
13 private UserRepository userRepository;
14
15 public void add() {
16 System.out.println("I am UserService's add method...");
17 userRepository.sava();
18 }
19 }
1 package com.itdjx.spring.annotation.repository;
2
3 /**
4 * @author Wáng Chéng Dá
5 * @create 2017-03-03 9:23
6 */
7 public interface UserRepository {
8
9 void sava();
10
11 }
1 package com.itdjx.spring.annotation.repository;
2
3 import org.springframework.stereotype.Repository;
4
5 /**
6 * @author Wáng Chéng Dá
7 * @create 2017-03-03 9:24
8 */
9 @Repository("userRepository")
10 public class UserRepositoryImpl implements UserRepository {
11
12 @Override
13 public void sava() {
14 System.out.println("I am UserRepositoryImpl's sava method...");
15 }
16 }
1 package com.itdjx.spring.annotation;
2
3 import com.itdjx.spring.annotation.controller.UserController;
4 import org.springframework.context.ApplicationContext;
5 import org.springframework.context.support.ClassPathXmlApplicationContext;
6
7 /**
8 * @author Wáng Chéng Dá
9 * @create 2017-03-03 9:34
10 */
11 public class Main {
12
13 public static void main(String[] args) {
14
15 ApplicationContext cxt = new ClassPathXmlApplicationContext("beans-annotation.xml");
16 UserController userController = (UserController) cxt.getBean("userController");
17 userController.execute();
18
19 }
20 }
控制台輸出:
Exception in thread "main" java.lang.NullPointerException at com.itdjx.spring.annotation.controller.UserController.execute(UserController.java:16) at com.itdjx.spring.annotation.Main.main(Main.java:17) |
原因:IOC 容器中雖然每個 bean 節點都存在 , 但是沒有引入到需要引入的 bean 節點中 , 需要將需要引入的 bean 節點引入相應的 bean 節點中。
1 package com.itdjx.spring.annotation.controller;
2
3 import com.itdjx.spring.annotation.service.UserService;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Controller;
6
7 /**
8 * @author Wáng Chéng Dá
9 * @create 2017-03-03 9:28
10 */
11 @Controller
12 public class UserController {
13 @Autowired
14 private UserService userService;
15
16 public void execute() {
17 System.out.println("I am UserController's execute method...");
18 userService.add();
19 }
20 }
1 package com.itdjx.spring.annotation.service;
2
3 import com.itdjx.spring.annotation.repository.UserRepository;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Service;
6
7 /**
8 * @author Wáng Chéng Dá
9 * @create 2017-03-03 9:26
10 */
11 @Service
12 public class UserService {
13
14 @Autowired
15 private UserRepository userRepository;
16
17 public void add() {
18 System.out.println("I am UserService's add method...");
19 userRepository.sava();
20 }
21 }
控制台輸出:
I am UserController's execute method... I am UserService's add method... I am UserRepositoryImpl's sava method... |
假如我們將 IOC 容器中不存在的 bean 節點引入到 bean 節點中 , 會出現什么狀況呢?
1 package com.itdjx.spring.annotation;
2
3
4 /**
5 * @author Wáng Chéng Dá
6 * @create 2017-03-03 8:44
7 */
8
9 public class TestObject {
10 }
1 package com.itdjx.spring.annotation.repository;
2
3 import com.itdjx.spring.annotation.TestObject;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Repository;
6
7 /**
8 * @author Wáng Chéng Dá
9 * @create 2017-03-03 9:24
10 */
11 @Repository("userRepository")
12 public class UserRepositoryImpl implements UserRepository {
13
14 @Autowired
15 private TestObject testObject;
16 @Override
17 public void sava() {
18 System.out.println("I am UserRepositoryImpl's sava method...");
19 System.out.println(testObject);
20 }
21 }
控制台輸出:
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepository': Unsatisfied dependency expressed through field 'testObject'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.itdjx.spring.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepository': Unsatisfied dependency expressed through field 'testObject'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.itdjx.spring.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.itdjx.spring.annotation.Main.main(Main.java:15) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepository': Unsatisfied dependency expressed through field 'testObject'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.itdjx.spring.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 15 more Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userRepository': Unsatisfied dependency expressed through field 'testObject'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.itdjx.spring.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 28 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.itdjx.spring.annotation.TestObject' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1486) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 41 more |
解決方法:
1 package com.itdjx.spring.annotation.repository;
2
3 import com.itdjx.spring.annotation.TestObject;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Repository;
6
7 /**
8 * @author Wáng Chéng Dá
9 * @create 2017-03-03 9:24
10 */
11 @Repository("userRepository")
12 public class UserRepositoryImpl implements UserRepository {
13
14 @Autowired(required = false)
15 private TestObject testObject;
16
17 @Override
18 public void sava() {
19 System.out.println("I am UserRepositoryImpl's sava method...");
20 System.out.println(testObject);
21 }
22 }
控制台輸出:
I am UserController's execute method... I am UserService's add method... I am UserRepositoryImpl's sava method... null |
使用 @Resource 或 @Inject 自動裝配 Bean:
Spring 還支持 @Resource 和 @Inject 注解 , 這兩個注解和 @Autowired 注解的功能類似。
@Resource 注解要求提供一個 bean 名稱的屬性 , 若該屬性為空 , 則自動采用標注出的變量或方法名作為 bean 的名稱。
@Inject 和 @Autowired 注解一樣也是按類型匹配注入的 bean , 但沒有 required 屬性。
建議使用 @Autowired 注解。