Spring IOC 容器中Bean的装配
Bean管理的注解实现
类的自动检测与注册Bean
<!--通过在基于xml的Spring排至如下标签(请注意包含上下文命名空间)-->
<context:annotation-config/>
context:annotation-config
,仅会查找在同一个applicationContext的bean注解,为了能够检测这些类并注册相应的bean,需要下面内容:
<context:component-scan base-package="com.spring"></context:component-scan>
context:annotation-scan
包含context:annotation-config
,通常在使用前者后,不在使用后者AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也被包含进来。
点击前往:context:component-scan标签详解
Spring 的定义及作用于的注解实现:
从 Spring3.0 开始,SpringJavaConfig 项目提供了很多特性,包括使用 java 而不是 xml 定义bean,比如@Configuration
,@bean
,@import
,@DependsOn
@Componnent
是一个通用注解,可用于任何bean@Repository
,@Service
,@Controller
是更有针对性的注解
-
@Repository
通用于注解DAO类,即持久层 -
@Service
通用于注解Service,即服务层 -
@Controller
通用于Controller类,即控制层(MVC)
@Repository
public class UserDao {
public void save(String name) {
System.out.println("保存用户:" + name);
}
}
public interface UserService {
void insertUser(String name);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public void insertUser(String name) {
userDao.save(name);
}
}
@ContextConfiguration(locations = {"classpath*:application-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void insert() {
userService.insertUser("Tom");
}
}
@Required
这个注解仅仅表示,受影响的bean属性必须在配置时被填充,通过在bean定义或者通过自动装配一个明确的属性值
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Required
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
@Autowired
1.可以将@Autowired注解为“传统”的setter方法
priavte MovieFinder movieFinder;
@Autowired
public void setMovieFind (MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
2.可用于构造器或成员变量
@Autowired
private MovieCatalog movieCatelog;
private CustomerpreferenceDao customerpreferenceDao;
@Autowired
public MovieRecommender(CustomerpreferenceDaocustomerpreferenceDao){
this.customerpreferenceDao = customerpreferenceDao;
}
默认情况下,如果因为找不到合适的bean将导致autowiring失败抛出异常,可以通过下面的方式避免:
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Autowired(required=false)
public void setMovieFind (MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
每个类只能有一个构造器被标记为required=true,@Autowired的必要属性,建议使用@Required注解
例子:
@Service
public class UserServiceImpl implements UserService {
// 属性注入
//@Autowired
private UserDao userDao;
// 构造器注入
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
// 设值注入
/*@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}*/
@Override
public void insertUser(String name) {
userDao.save(name);
}
}
无论利用 UserServiceImpl 中的哪一种 @Autowired 的方式结果都能正常执行。
3.可以使用@Autowired注解那些众所周知的解析依赖性接口,比如:BrenFactory,ApplicationContext,Environment,ResourceLoader,ApplicationEventPublisher,andMessageSource
public class MovieRecommender{
@Autowired
private ApplicationContext context;
public MovieeRecommender(){
}
}
4.可以通过添加注解给需要该类型的数组的字段或方法,以提供 ApplicationContext 中的所有特定类型的bean
private set<MovieCatalog> movieCatalogs;
@Autowired
public void setMovieCatalogs(Set<MovieCatalogs>movieCatalogs){
this.movieCatalogs = movieCatalogs;
}
5.可以用于装配 key 为 string 的 Map
private Map<String,MovieCatalogs> movieCatalogs;
@Autowired
public void setMovieCatalogs(Map<String,MovieCatalogs>movieCatalogs){
this.movieCatalogs = movieCatalogs;
}
如果希望数组有序,可以让bean实现 org.springframework.core.Ordered
接口或使用 @Order
注解
@Autowired是有 SpringBeanPostProcessor 处理的,所以不能在自己的 BeanPostProcessor 或 BeanFactoryPostProcessor 类型应用这些注解,这些类型必须通过XML或者Spring的@Bean注解加载。
public interface BeanInterface {
}
@Order(2)
@Component
public class BeanImplOne implements BeanInterface {}
@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {}
@Component
public class BeanInvoker {
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String, BeanInterface> map;
public void say() {
if (null != list && 0 != list.size()) {
System.out.println("list...");
for (BeanInterface bean : list) {
System.out.println(bean.getClass().getName());
}
} else {
System.out.println("List<BeanInterface> list is null!!!!!!!!!!");
}
System.out.println();
if (null != map && 0 != map.size()) {
System.out.println("map...");
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + " " +entry.getValue().getClass().getName());
}
} else {
System.out.println("Map<String, BeanInterface> map is null!!!!!!!!!!");
}
}
}
@ContextConfiguration(locations = {"classpath*:application-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestInjection {
@Autowired
private BeanInvoker beanInvoker;
@Test
public void testMultiBean() {
beanInvoker.say();
}
}
结果:
list…
com.imooc.beanannotation.multibean.BeanImplTwo
com.imooc.beanannotation.multibean.BeanImplOne
map…
beanImplOne com.imooc.beanannotation.multibean.BeanImplOne
beanImplTwo com.imooc.beanannotation.multibean.BeanImplTwo
如果去掉@Order(1)和@Order(2)结果是:
list…
com.imooc.beanannotation.multibean.BeanImplOne
com.imooc.beanannotation.multibean.BeanImplTwo
map…
beanImplOne com.imooc.beanannotation.multibean.BeanImplOne
beanImplTwo com.imooc.beanannotation.multibean.BeanImplTwo
也就是说Order只能影响list的顺序,只有list先执行了有Order(1)的BeanImplTwo,而Map没有受到影响。
@Qualifier
按类型自动装配可能多个bean实例的情况,可以使用Spring的@Qulifier注解缩小范围(或指定唯一),也可以用于指定单独的构造器参数或方法参数
1.可用于注解集合类型变量
如果通过名字进行注解注入,主要使用的不是@Autowired(即使在技术上能够通过@Qualifier指定bean的名字),替代方式是使用JSR-250 @Resource
注解,它是通过其独特的名称来定义来识别特定的目标(这是一个与所声明的类型是无关的匹配过程)
因语意差异,集合或Map类型的bean无法通过@Autowired来注入,因为没有类型匹配到这样的bean,为这些bean使用@Resource注解,通过唯一名称引用集合或Map的bean
@Autpwired适用于fields,constructors,multi-argumentmethods这些允许在参数级别使用@Qualifier注解缩小范围的情况
@Resource适用于成员变量,只有一个参数的setter方法,所以在目标是构造器或者一个多参数方法时,最好的方式是使用qualifiers·
@Component
public class BeanInvoker {
@Autowired
@Qualifier("beanImplOne")
private BeanInterface beanInterface;
@Autowired
private List<BeanInterface> list;
@Autowired
private Map<String, BeanInterface> map;
public void say() {
if (null != list && 0 != list.size()) {
System.out.println("list...");
for (BeanInterface bean : list) {
System.out.println(bean.getClass().getName());
}
} else {
System.out.println("List<BeanInterface> list is null!!!!!!!!!!");
}
System.out.println();
if (null != map && 0 != map.size()) {
System.out.println("map...");
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + " " +entry.getValue().getClass().getName());
}
} else {
System.out.println("Map<String, BeanInterface> map is null!!!!!!!!!!");
}
System.out.println();
if (null != beanInterface) {
System.out.println(beanInterface.getClass().getName());
} else {
System.out.println("beanInterface is null...");
}
}
}
运行单元测试方法:
list…
com.imooc.beanannotation.multibean.BeanImplOne
com.imooc.beanannotation.multibean.BeanImplTwo
map…
beanImplOne com.imooc.beanannotation.multibean.BeanImplOne
beanImplTwo com.imooc.beanannotation.multibean.BeanImplTwo
com.imooc.beanannotation.multibean.BeanImplOne
如果是@Qualifier(“beanImplTwo”)结果是:com.imooc.beanannotation.multibean.BeanImplTwo
基于java的容器注解
@Bean
标识一个用于配置和初始化一个由 Spring IOC 容器管理的新对象的方法,类似于XML配置文件的<bean/>
可以在spring的@Component注解的类中使用@Bean注解任何方法(仅仅是可以)
上一点中,通常使用的是@Configuration
@Configuration
public class AppConfig{
@Bean
public MyService myService(){
return new MyServiceImol();
}
}
相当于
<beans>
<bean id="myService" class="com.spring.service.MyService"/>
</beans>
public interface Store {
void init();
void destroy();
}
public class StringStore implements Store {
public void init() {
System.out.println("This is init.");
}
public void destroy() {
System.out.println("This is destroy.");
}
}
@Configuration
public class StoreConfig {
@Bean(name ="store", initMethod="init", destroyMethod="destroy")
public Store getStringStore() {
return new StringStore();
}
}
@ContextConfiguration(locations = {"classpath*:application-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class StoreTest {
@Autowired
private Store store;
@Test
public void test() {
System.out.println(store.getClass().getName());
}
}
执行测试方法:
This is init.
com.imooc.beanannotation.javabased.StringStore
This is destroy.
@ImportResource 和 @Value
public class MyDriverManager {
public MyDriverManager(String url, String userName, String password) {
System.out.println("url : " + url);
System.out.println("userName: " + userName);
System.out.println("password: " + password);
}
}
@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {
@Value("${url}")
private String url;
@Value("${username}")
private String username;
@Value("${password}")
private String password;
@Bean
public MyDriverManager myDriverManager() {
return new MyDriverManager(url, username, password);
}
@Bean(name ="store", initMethod="init", destroyMethod="destroy")
public Store getStringStore() {
return new StringStore();
}
}
config.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.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:property-placeholder location="classpath:config.properties"/>
</beans>
config.properties
username=root
password=root
url=127.0.0.1
运行StoreTest 测试代码:
url : 127.0.0.1
userName: Administrator
password: root
明显这里的username并不是我们本来设置好的值,这里返回的是登陆windows的值,所以我们需要将config.properties中的username更改为jdbc.username=root,并且更改@Value("${jdbc.username}")
@Bean 和 @Scope
默认@Bean是单例的,Bean的作用域包括singleton,prototype,request,session,globalsession
@Configuration
public calss MyConfiguration{
@Bean
@Scope("prototype")
public Encryptor encryptory(){}
}
@Configuration
public class StoreConfig {
@Bean(name = "stringStore")
@Scope(value="prototype")
public Store stringStore() {
return new StringStore();
}
}
@Test
public void testScope() {
Store store = super.getBean("stringStore");
System.out.println(store.hashCode());
store = super.getBean("stringStore");
System.out.println(store.hashCode());
}
测试结果:
1612798177
760368405
其他的用法@Scope(value=“prototype”,proxyMode=ScopedProxyMode.TARGET_CLASS)
基于泛型的自动装配
public interface Store<T> {
}
public class StringStore implements Store<String> {
}
public class IntegerStore implements Store<Integer> {
}
@Configuration
public class StoreConfig {
@Autowired
private Store<String> s1;
@Autowired
private Store<Integer> s2;
@Bean
public StringStore stringStore() {
return new StringStore();
}
@Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
@Bean(name = "stringStoreTest")
public Store stringStoreTest() {
System.out.println("s1:"+s1.getClass().getSimpleName());
System.out.println("s2:"+s2.getClass().getSimpleName());
return new StringStore();
}
}
@Test
public void testG() {
StringStore store = super.getBean("stringStoreTest");
}
测试结果:
s1:StringStore
s2:IntegerStore
Spring对JSR支持的说明
Spring还支持使用JSR-250
(Java Specification Requests的缩写,意思是Java 规范提案) @Resource
注解的变量或setter方法,这是一种在java EE5和6的通用模式,Spring管理的对象也支持这种模式
@Resource有一个那么属性,并且默认Spring解释该值作为被注入bean的名称
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Resource(name="myMoviFinder")
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
如果没有显式地指定@Resource的name,默认的名称是从属性名或者setter方法得出
public class SimpleMovieLister{
private MovieFinder movieFinder;
@Resource
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder = movieFinder;
}
}
注解提供的名字被解析为一个bean的名称,这是由ApplicationContext的中的CommonAnnotationBeanPostProcessor发现并处理的
CommonAnnotationBeanPostProcessor不仅能识别出JSR-250中的生命周期注解@Resource,在spring2.5中引入支持初始化回调和销毁回调,前提是CommonAnnotationBeanPostProcessor是spring的ApplicationContext注册的
@Repository
public class JsrDAO {
public void save() {
System.out.println("JsrDAO invoked.");
}
}
@Service
public class JsrServie {
private JsrDAO jsrDAO;
@Resource
public void setJsrDAO(JsrDAO jsrDAO) {
this.jsrDAO = jsrDAO;
}
/*@Resource
private JsrDAO jsrDAO;
public void setJsrDAO(JsrDAO jsrDAO) {
this.jsrDAO = jsrDAO;
}*/
public void save() {
jsrDAO.save();
}
@PostConstruct
public void init() {
System.out.println("JsrServie init.");
}
@PreDestroy
public void destroy() {
System.out.println("JsrServie destroy.");
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestJsr extends UnitTestBase {
public TestJsr() {
super("classpath*:spring-beanannotation.xml");
}
@Test
public void testSave() {
JsrServie service = getBean("jsrServie");
service.save();
}
}
测试结果:
JsrServie init.
JsrDAO invoked.
JsrServie destroy.
这和我们在使用xml文件配置的时候使用的initMethod和destoryMethod两个xml的配置属性起到的效果是一样的。
使用JSR330标准注解
从Spring3.0开始支持JSR330
标准注解,其扫描方式与Spring注解一致
使用JSr330需要依赖javax.inject包
使用Maven引入方式
@Inject
@Inject等效于@Autowired,可以使用类,属性,方法,构造器
@Named
如果想使用特定名称进行依赖注入,使用@named
@Named与@Component是等效的
更改上面代码:
//@Service
@Named
public class JsrServie {
// @Resource
// @Inject
private JsrDAO jsrDAO;
// @Resource
@Inject
public void setJsrDAO(JsrDAO jsrDAO) {
this.jsrDAO = jsrDAO;
}
}
在两个地方添加@Inject运行结果是一致的:
JsrServie init.
JsrDAO invoked.
JsrServie destroy.
更改:
@Inject
public void setJsrDAO(@Named("jsrDAO") JsrDAO jsrDAO) {
this.jsrDAO = jsrDAO;
}
运行结果和上面的一致,这个named的用处在于和前面提到的一个接口有两个实现方法,这里的named给出了具体的哪一个实现方式。
Bean容器初始化
基础:两个包
- org.springframework.beans
- org.springframework.context
- BeanFactory提供配置结构和基本功能,加载并初始化Bean
- ApplicationContext保存了Bean对象并在Spring中被广泛使用
方式,ApplicationContext
- 本地文件
- Classpath
- Web应用中依赖servlet或Listener
bean容器初始化
// 文件
FileSystemXmlApplicationContext context = newFileSystemXmlApplicaitonContext("F:/workspace/application.xml");
// Classpath
ClassPathXmlApplicationContext context = newClassPathXmlApplicationContext("classpath:spring-context.xml")
web应用
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet></servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Spring注入
Spring注入是指在启动Spring容器加载bean配置的时候,完成对变量的赋值行为
常用的两种注入方式
- 设值注入
- 构造注入
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="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.xsd">
<!-- 设值注入 -->
<!-- <bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">-->
<!-- <property name="injectionDAO"ref="injectionDAO"></property> -->
<!-- </bean> -->
<!-- 构造注入 -->
<bean id="injectionService" class="com.imooc.ioc.injection.service.InjectionServiceImpl">
<constructor-arg name="injectionDAO" ref="injectionDAO"></constructor-arg>
</bean>
<bean id="injectionDAO" class="com.imooc.ioc.injection.dao.InjectionDAOImpl"></bean>
</beans>
public interface InjectionDAO {
public void save(String arg);
}
public class InjectionDAOImpl implements InjectionDAO {
public void save(String arg) {
//模拟数据库保存操作
System.out.println("保存数据:" + arg);
}
}
public interface InjectionService {
public void save(String arg);
}
public class InjectionServiceImpl implements InjectionService{
private InjectionDAO injectionDAO;
//构造器注入
public InjectionServiceImpl(InjectionDAO injectionDAO1){
this.injectionDAO = injectionDAO1;
}
//设值注入
public void setInjectionDAO(InjectionDAO injectionDAO) {
this.injectionDAO = injectionDAO;
}
public void save(String arg) {
//模拟业务操作
System.out.println("Service接收参数:" + arg);
arg = arg + ":" + this.hashCode();
injectionDAO.save(arg);
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {
public TestInjection() {
super("classpath:spring-injection.xml");
}
@Test
public void testSetter() {
InjectionService service =super.getBean("injectionService");
service.save("这是要保存的数据");
}
@Test
public void testCons() {
InjectionService service =super.getBean("injectionService");
service.save("这是要保存的数据");
}
}
Bean专题
Bean配置项
Id Bean的唯一标识
Class 具体要实例化的那一个类
Scope 作用域
Constructor arguments 构造器的参数
Properties 属性
Autowiring mode 自动装配的方法
lazy-initialization mode 懒加载方式
Initialization/destruction method 初始化和销毁的方法
Bean的作用域
singleton:单例,指一个Bean容器中存在一份
prototype:每次请求创建新的实例,destroy方式不生效
request:每次http请求创建一个实例且仅在当前request内有效
session:同上,每次http请求创建,当前session内有效
global session:基于portlet的web中有效(portlet定义了globalsession),如果实在web中,同session
Bean的生命周期
生命周期
- 定义
- 初始化
- 使用
- 销毁
初始化
两种方式:
1.实现 org.springframework.beans.factory.InitializingBean
接口,覆盖afterPropertiesSet方法
public class ExampleInitializingBean implements InitializingBean{
@Override
public void afterPropertiesSet() throws Exceptin{
//do something
}
}
在spring初始化bean的时候,如果bean实现了InitializingBean接口,会自动调用afterPropertiesSet方法。
2.配置init-method
<bean id="meampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean{
public void init(){
//do some initialization work
}
}
销毁
两种方式:
1.实现 org.springframework.beans.factory.DisposableBean
接口,覆盖destroy方法
2.配置destroy-method
<bean id="exampleDisBean" class="examples.ExampleBean" destory-method="cleanup">
public class ExampleDisposableBean implements DisposableBean{
@Override
public void destroy() throws Exception{
//do something
}
}
public class Example {
public void cleanup{
//执行一些销毁的操作
}
}
配置全局默认初始化和销毁方法
<bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle" init-method="start" destroy-method="stop"></bean>
public class BeanLifeCycle{
public void start() {
System.out.println("Bean start .");
}
public void stop() {
System.out.println("Bean stop.");
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanLifecycle extends UnitTestBase {
public TestBeanLifecycle() {
super("classpath:spring-lifecycle.xml");
}
@Test
public void test1() {
super.getBean("beanLifeCycle");
}
}
输出:
Bean start .
Bean stop.
这里不是在于我们是不是执行了getbean方法,是在我们执行@test的时候,程序会首先执行基类UnitTestBase的before,在test执行后再执行基类的after,在before中,我们会启动ioc容器,在after中我们会调用ioc的distory方法。所以测试的目的是为了在测试前调用ioc容器加载bean同时调用bean的init-method,结束时同样。
另一种方式:
修改配置文件:
<bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle"></bean>
public class BeanLifeCycle implements InitializingBean,DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("Bean destroy.");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Bean afterPropertiesSet.");
}
}
执行测试文件:
Bean afterPropertiesSet.
Bean destroy.
配置默认的方法:
<bean id="beanLifeCycle" class="com.imooc.lifecycle.BeanLifeCycle" default-init-method="defautInit" default-destroy-method="defaultDestroy"></bean>
public class BeanLifeCycle{
public void defautInit() {
System.out.println("Bean defautInit.");
}
public void defaultDestroy() {
System.out.println("Bean defaultDestroy.");
}
}
测试结果:
Bean afterPropertiesSet.
Bean destroy.
如果三种方式同时执行:
Bean afterPropertiesSet.
Bean start .
Bean destroy.
Bean stop.
可以看出如果使用初始化bean和销毁bean的接口初始化bean和销毁bean时,默认方式的初始化和销毁就会不是起作用,而且会先执行接口方法,在执行简单的自定义方式。
Aware
Spring中提供了一些以 Aware
结尾的接口,实现了Aware接口的bean在被初始化,可以获取相应资源
通过Aware接口,可以对Spring相应资源进行操作(一定要慎重)
为对Spring进行简单的扩展提供了方便的入口
spring-aware.xml:
<bean id="moocApplicationContext" class="com.imooc.aware.MoocApplicationContext" ></bean>
创建类:MoocBeanName
public class MoocApplicationContext implements ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContextapplicationContext) throws BeansException {
System.out.println("MoocApplicationContext : " + applicationContext.getBean("moocApplicationContext").hashCode());
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAware extends UnitTestBase {
public TestAware() {
super("classpath:spring-aware.xml");
}
@Test
public void testMoocApplicationContext() {
System.out.println("testMoocApplicationContext : " + super.getBean("moocApplicationContext").hashCode());
}
}
结果:
MoocApplicationContext : 1592838887
testMoocApplicationContext : 1592838887
另一种:
<bean id="moocBeanName" class="com.imooc.aware.MoocBeanName"></bean>
public class MoocBeanName implements BeanNameAware{
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("MoocBeanName : " + name);
}
}
@Test
public void textMoocBeanName() {
System.out.println("textMoocBeanName : " + super.getBean("moocBeanName").hashCode());
}
结果:
MoocBeanName : moocBeanName
textMoocBeanName : 2098935205
同时使用:
public class MoocBeanName implements BeanNameAware,ApplicationContextAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("MoocBeanName : " + name);
}
@Override
public void setApplicationContext(ApplicationContextapplicationContext)throws BeansException {
System.out.println("setApplicationContext : " + applicationContext.getBean(this.beanName).hashCode());
}
}
测试结果:
MoocBeanName : moocBeanName
setApplicationContext : 312030307
textMoocBeanName : 312030307
也就是说无论是通过aware接口传入还是通过getbean方法,ioc的上下文的引用效果是一样的,得到相同的实例。
Bean的自动装配(Autowiring)
No:不做任何操作
byName:根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配
byType:如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出异常,并指出不能使用byType方式进行自动装配了如果没有找到相匹配的bean,则什么事都不会发生。
constructor:与bytype方式类似,不同之处在于它应用于构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常。
配置文件:
默认:
<bean id="autoWiringService" class="com.imooc.autowiring.AutoWiringService" autowire="byName"/>
<bean id="autoWiringDAO" class="com.imooc.autowiring.AutoWiringDAO"/>
public class AutoWiringDAO {
public void say(String word) {
System.out.println("AutoWiringDAO : " + word);
}
}
public class AutoWiringService {
private AutoWiringDAO autoWiringDAO;
public void setAutoWiringDAO(AutoWiringDAO autoWiringDAO){
this.autoWiringDAO = autoWiringDAO;
}
public void say(String word) {
this.autoWiringDAO.say(word);
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAutoWiring extends UnitTestBase {
public TestAutoWiring() {
super("classpath:spring-autowiring.xml");
}
@Test
public void testSay() {
AutoWiringService service =super.getBean("autoWiringService");
service.say(" this is a test");
}
}
测试结果:
AutoWiringDAO : this is a test
改为byType
结果和过程都是一样的。
如果去掉DAO在配置文件中的id,那么在bytype的情况下会正常进行,而在byname时不做操作。
如果改为constructor,则需要在AutoWiringService 添加一个构造器:
public AutoWiringService(AutoWiringDAO autoWiringDAO) {
System.out.println("AutoWiringService");
this.autoWiringDAO = autoWiringDAO;
}
测试结果(没有DAO的id同样):
AutoWiringService
AutoWiringDAO : this is a test
Resources
针对于资源文件的统一接口。
- UrlResource:URL对应的资源,根据一个URL地址即可构建
- ClassPathResource:获取类路径下的资源文件
- FileSystemResource:获取文件系统里面的资源
- ServletContextResource:ServletContext封装的资源,用于访问ServletContext环境下的资源
- InputStreamResource:针对于输入流封装的资源
- ByteArrayResource:针对于字节数组封装的资源
ResourceLoader
- 所有的applicationcontexts都实现了ResourceLoader接口,也就是说所有applicationcontexts都可以实现Resource方法。
public interface ResourceLoader{
Resource getResource(String location);
}
Resource template =ctx.getResource("some.resource/path/myTemple.txt");
Resource template =ctx.getResource("classpath:some.resource/path/myTemple.txt");
Resource template =ctx.getResource("file:some.resource/path/myTemple.txt");
配置文件:
<bean id="moocResource" class="com.imooc.resource.MoocResource"></bean>
public class MoocResource implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContextapplicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void resource() throws IOException {
Resource resource =applicationContext.getResource("classpath:config.txt"); //该文件放置在项目的一个包下,并且该包已经在classpath中配置,所以可以直接写文件名不用写路径
System.out.println(resource.getFilename());
System.out.println(resource.contentLength());
}
}
@RunWith(BlockJUnit4ClassRunner.class)
public class TestResource extends UnitTestBase {
public TestResource() {
super("classpath:spring-resource.xml");
}
@Test
public void testResource() {
MoocResource resource = super.getBean("moocResource");
try {
resource.resource();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试结果:
config.txt
10
修改:
Resource resource =applicationContext.getResource("file:C:\\Users\\Administrator\\Workspaces\\MyEclipseProfessional2014\\Spring\\src\\test\\resources\\config.txt");
测试结果一样。
修改:
Resource resource =applicationContext.getResource("url:http://docs.spring.io/spring/docs/4.0.5.RELEASE/spring-framework-reference/htmlsingle/");
测试结果:
htmlsingle
-1
修改:
Resource resource =applicationContext.getResource("config.txt");
结果:
config.txt
10
当文件前什么都不写的情况下,那就将依赖于applicationcontext的创建方式,也就是classpath的方式去加载。
下一篇: Spring3 的 @value