Spring_根据类型获取bean的各种情况
一、根据类型获取 bean
1、情景一
bean 对应的类没有实现任何接口
根据 bean 本身的类型获取 bean
测试:IOC 容器中同类型的 bean 只有一个
结果:可以正常获取到 IOC 容器中的那个 bean 对象
测试:IOC 容器中同类型的 bean 有多个
结果:会抛出NoUniqueBeanDefinitionException异常,表示 IOC 容器中这个类型的 bean 有多个
准备:
测试程序 SpringTest:
1
2
3
4
5
6
7
8
9public class SpringTest {
private ApplicationContext iocContainer = new ClassPathXmlApplicationContext("applicationContext.xml");
public void testSituation1() {
EmpDao empDao = iocContainer.getBean(EmpDao.class);
System.out.println("empDao = " + empDao);
}IOC 容器中同类型的 bean 只有一个:
1
2
3
4
5
6
7
8package get.bean.situation1;
import org.springframework.stereotype.Repository;
public class EmpDao {
}IOC 容器中同类型的 bean 有多个:
1
2
3
4
5
6
7
8package get.bean.situation1;
import org.springframework.stereotype.Repository;
public class EmpSubDao extends EmpDao {
}
2、情景二
bean 对应的类实现了接口,这个接口也只有这一个实现类
测试:根据接口类型获取 bean
测试:根据类获取 bean
结果:上面两种情况其实都能够正常获取到 bean,而且是同一个对象
测试程序:
1
2
3
4
5
6
7
8
9
10
11
12
public void testSituation2() {
// 情景:EmpDao是接口,EmpDaoImpl实现了EmpDao接口
// 1.根据EmpDao接口类型获取bean
get.bean.situation2.EmpDao empDao01 = iocContainer.getBean(get.bean.situation2.EmpDao.class);
System.out.println("empDao01 = " + empDao01);
// 2.根据EmpDaoImpl类获取bean
EmpDaoImpl empDao02 = iocContainer.getBean(EmpDaoImpl.class);
System.out.println("empDao02 = " + empDao02);
}
3、情景三
声明一个接口
接口有多个实现类
接口所有实现类都放入 IOC 容器
测试:根据接口类型获取 bean
结果:会抛出NoUniqueBeanDefinitionException异常,表示 IOC 容器中这个类型的 bean 有多个
测试:根据类获取 bean
结果:正常
测试程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void testSituation3() {
// 情景3:EmpService是一个接口,EmpServiceImpl01、EmpServiceImpl02是两个实现类
// 1.根据EmpService接口类型获取bean
// EmpService empService = iocContainer.getBean(EmpService.class);
// System.out.println("empService = " + empService);
// 2.根据EmpServiceImpl01类获取bean
EmpServiceImp01 empServiceImp01 = iocContainer.getBean(EmpServiceImp01.class);
System.out.println("empServiceImp01 = " + empServiceImp01);
// 3.根据EmpServiceImpl02获取bean
EmpServiceImp02 empServiceImp02 = iocContainer.getBean(EmpServiceImp02.class);
System.out.println("empServiceImp02 = " + empServiceImp02);
}
4、情景四(动态代理)
声明一个接口
接口有一个实现类
创建一个切面类,对上面接口的实现类应用通知
测试:根据接口类型获取 bean
结果:正常,可以获取到 bean
测试:根据实现类获取 bean
结果:会抛出NoSuchBeanDefinitionException
接口:
1
2
3
4package get.bean.situation4;
public interface EmpController {
}实现类:
1
2
3
4
5
6
7
8
9
10
11package get.bean.situation4;
import org.springframework.stereotype.Controller;
public class EmpControllerImpl implements EmpController {
public void showMessage() {
}
}创建一个环绕通知:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Situation4Aspect {
public Object doAround(ProceedingJoinPoint joinPoint) {
Object result = null;
try {
result = joinPoint.proceed(joinPoint.getArgs());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
}测试程序:
1
2
3
4
5
6
7
8
9
10
11
12
public void testSituation4() {
// 情景:EmpController是接口;EmpControllerImpl是实现类;对实现类应用了切面
// 1.根据接口类型获取bean
EmpController empController = iocContainer.getBean(EmpController.class);
System.out.println("empController = " + empController);
// 2.根据实现类类型获取bean
EmpControllerImpl empController1 = iocContainer.getBean(EmpControllerImpl.class);
System.out.println("empController1 = " + empController1);
}
原因分析:
- 应用了切面后,真正放在 IOC 容器中的是代理类的对象
- 目标类并没有被放到 IOC 容器中,所以根据目标类的类型从 IOC 容器中是找不到的
从内存分析的角度来说,IOC 容器中引用的是代理对象,代理对象引用的是目标对象。IOC 容器并没有直接引用目标对象,所以根据目标类本身在 IOC 容器范围内查找不到。
debug 查看代理类的类型:
5、情景五(cglib)
声明一个类
创建一个切面类,对上面的类应用通知
测试:根据类获取 bean
结果:正常,可以获取到 bean
测试:
1
2
3
4
5
6
7
8
9
public void testSituation5() {
// 情景:StuService是类;Situation5Aspect是切面,对StuService类应用切面
// 根据StuService类本身的类型来获取bean
StuService stuService = iocContainer.getBean(StuService.class);
System.out.println("stuService = " + stuService);
}原因分析:
debug 查看实际类型:
二、自动装配
1、情景一
目标 bean 对应的类没有实现任何接口
根据 bean 本身的类型获取 bean
测试:IOC 容器中同类型的 bean 只有一个
结果:正常装配
测试:IOC 容器中同类型的 bean 有多个
结果:会抛出NoUniqueBeanDefinitionException异常,表示 IOC 容器中这个类型的 bean 有多个
2、情景二
目标 bean 对应的类实现了接口,这个接口也只有这一个实现类
测试:根据接口类型装配 bean
结果:正常
测试:根据类装配 bean
结果:正常
3、情景三
声明一个接口
接口有多个实现类
接口所有实现类都放入 IOC 容器
测试:根据接口类型装配 bean
结果:根据接口类型会找到多个符合的 bean,然后根据成员变量名作为 bean 的 id 进一步筛选,如果没有 id 匹配的,则会抛出 NoUniqueBeanDefinitionException 异常,表示 IOC 容器中这个类型的 bean 有多个
测试:根据类装配 bean
结果:正常
4、情景四(动态代理)
声明一个接口
接口有一个实现类
创建一个切面类,对上面接口的实现类应用通知
测试:根据接口类型装配 bean
结果:正常
测试:根据类装配 bean
结果:此时获取不到对应的 bean,所以无法装配
5、情景五(cglib)
声明一个类
创建一个切面类,对上面的类应用通知
测试:根据类装配 bean
结果:正常