Bean
Bean配置
Bean中可以通过name属性给该Bean添加别名,可通过别名引用Bean,name可以有多个,可用逗号分号或空格分开。
1 2
| <bean id="bookDao" name="book book1,book2;book3" class="dao.impl.BookDaoImpl"/>
|
1 2 3 4 5
| ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao book = (BookDao) ctx.getBean("book"); BookDao newBook = (BookDao) ctx.getBean("book1"); System.out.println(book); System.out.println(newBook);
|
控制台输出为:
1 2
| dao.impl.BookDaoImpl@60dcc9fe dao.impl.BookDaoImpl@60dcc9fe
|
可见Spring在创建Bean的时候默认使用的是单例创建,若需要非单例创建,则需要在Bean中添加属性scope,scope默认为singleton为单例创建,prototype则为非单例创建
1
| <bean id="bookService" class="service.impl.BookServiceImpl" scope="prototype"/>
|
为什么Spring默认为单例创建?
适合交给容器管理的都应该是只创建一次可以复用的对象,例如表现层对象,业务层对象,数据层对象,工具对象。封装实体的域对象不应交给容器管理。
Bean实例化
构造方法
Spring创建Bean时需要使用反射调用构造方法,且必须是无参构造方法。
无参构造方法如果不存在,将抛出异常BeanCreationException。
静态工厂
若需要使用静态工厂方式获得实现类对象,则bean的配置中需加入factory-method属性。
1 2 3 4 5
| public class OrderDaoFactory { public static OrderDao getOrderDao(){ return new OrderDaoImpl(); } }
|
1
| <bean id="orderDao" class="service.OrderDaoFactory" factory-method="getOrderDao"/>
|
实例工厂与FactoryBean
原始方法
若工厂中使用的不是静态方法
1 2 3 4 5
| public class OrderDaoFactory { public OrderDao getOrderDao(){ return new OrderDaoImpl(); } }
|
则bean配置中需要加入factory-bean属性
1 2
| <bean id="orderDaoFactory" class="service.OrderDaoFactory"/> <bean id="orderDao" factory-bean="orderDaoFactory" factory-method="getOrderDao"/>
|
代替方法
可以通过创建一个FactoryBean对象来替代上述两个步骤。
1 2 3 4 5 6 7 8 9 10 11
| public class OrderDaoFactoryBean implements FactoryBean<OrderDao> { @Override public OrderDao getObject() throws Exception { return new OrderDaoImpl(); }
@Override public Class<?> getObjectType() { return OrderDao.class; } }
|
配置中只需加入一条即可。
1
| <bean id="orderDao" class="service.OrderDaoFactoryBean"/>
|
如果需要更改bean是否是单例实现,只需在FactoryBean对象中多重写一个方法。(默认就为单例)
1 2 3 4
| @Override public boolean isSingleton() { return true; }
|
Bean的生命周期
可以在实现类中配置方法,并在xml文件中添加属性。
1
| <bean id="bookDao" class="dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
|
也可以在实现类中实现两个接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean { @Override public void save() { System.out.println("book dao save..."); }
@Override public void destroy() throws Exception { System.out.println("destroy..."); }
@Override public void afterPropertiesSet() throws Exception { System.out.println("init..."); } }
|
Bean注入
setter注入
在最开始的DI案例中,若注入的是一个简单类型,也是需要提供一个set方法,而xml配置中则需要的是value属性而非ref属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class BookServiceImpl implements BookService {
private BookDao bookDao; private String databaseName;
@Override public void save() { System.out.println("book service save..." + databaseName); bookDao.save(); }
public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; }
public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } }
|
1 2 3 4 5 6 7
| <bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="bookService" class="service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"></property> <property name="databaseName" value="sql"></property> </bean>
|
构造器注入
还可以提供构造方法来注入,xml中需要加入constructor-arg标签,这种方式一样可以注入简单类型,将ref改为value即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class BookServiceImpl implements BookService {
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) { this.bookDao = bookDao; }
@Override public void save() { System.out.println("book service save..."); bookDao.save(); } }
|
1 2 3 4 5 6
| <bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="bookService" class="service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"></constructor-arg> </bean>
|
以上constructor-arg中的name也可以替换成type或index,用来指定构造方法中的形参。
依赖自动装配
如果提供了set方法,Spring可以自动装配注入,只需要添加autowire属性即可,但只能用于引用类型。
1 2 3
| <bean class="dao.impl.BookDaoImpl"/> <bean id="bookService" class="service.impl.BookServiceImpl" autowire="byType"/>
|
加载properties文件
开启context命名空间,location属性中加逗号可以加载多个文件,也可以直接使用classpath*:*.properties加载所有。可以在context中加属性system-properties-mode=”NEVER”避免系统变量优先级更高问题。
1 2 3 4 5 6 7 8 9 10 11
| <?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.xsd"> <context:property-placeholder location="classpath*:*.properties,jdbc.properties" system-properties-mode="NEVER"/>
|
使用context命名空间加载指定properties文件,使用${}读取加载的属性值。
1 2 3 4 5 6 7
| <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean>
|