首先spring是一个企业级J2EE的框架,用于开发一个webApp,它是针对bean的生命周期进行管理的轻量级容器。主要由七个部分组成:Spring Core、Spring AOP、Spring ORM、Spring DAO、Spring Context、Spring Web、Spring Web MVC
它有两大特性:IOC和AOP。
IOC是什么?
基本概念
1.IOC容器是一个创建对象、配置对象、连接对象、并管理对象的生命周期的一个容器,这里的对象即bean对象。
2.bean 是一个被实例化,组装,并通过IOC容器所管理的对象。
实现IOC容器的两种方式:
(1) BeanFactory
- Spring内部使用,开发人员基本不用,加载配置文件时不会创建对象,使用时才会创建对象。
(2) ApplicationContext
- BeanFactory的子接口,在其基础上添加更多功能,加载配置文件时就创建了好配置的对象。
基于XML管理Bean
DI:依赖注入,即注入属性
注入普通属性
<!--调用无参构造函数,使用set方法注入属性-->
<bean id="user" class="di.pojo.User">
<property name="password" value="12345"/>
<property name="username">
<null/> <!--设置为null-->
</property>
</bean>
<!--调用有参构造函数注入属性-->
<bean id="user1" class="di.pojo.User">
<constructor-arg name="password" value="67890"/>
<constructor-arg name="username">
<null/>
</constructor-arg>
</bean>
注入引用对象属性
当一个对象中含有另一个对象的引用,可通过引用外部bean、内部bean、级联三种方式设置引用对象的属性:
<!--引入外部bean赋值-->
<bean id="bookImpl" class="di.dao.impl.BookImpl">
<property name="bookName" value="红楼梦"/>
</bean>
<bean id="bookService" class="di.service.BookService">
<property name="bookDao" ref="bookImpl"/> <!--调用BookService中的setBookDao-->
</bean>
<!--引入内部bean赋值-->
<bean id="bookService1" class="di.service.BookService">
<property name="bookDao">
<bean class="di.dao.impl.BookImpl">
<property name="bookName" value="水浒传"/>
</bean>
</property>
</bean>
<!--级联属性赋值-->
<bean id="bookService2" class="di.service.BookService">
<property name="bookImpl" ref="bookImpl"/> <!--这行有必要-->
<property name="bookImpl.bookName" value="三国演义"/>
</bean>
注入集合属性
<!--注入集合属性-->
<bean id="collection" class="di.pojo.Collection">
<property name="arr">
<array>
<value>arr1</value>
<value>arr2</value>
</array>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<!--引用外部bean,添加到List<User>集合中-->
<property name="userList">
<list>
<ref bean="user"/>
<ref bean="user1"/>
</list>
</property>
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
</set>
</property>
<property name="map">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</map>
</property>
</bean>
普通bean和工厂bean的区别
IOC有两种bean,一种是普通bean,配置文件中定义的class类型和在代码中获取的类型必须要一致,上面配置的所有bean都是普通bean;另外一种是工厂bean,即配置文件定义的类型和返回的类型可以不一致,其类必须实现FactoryBean接口,如下:
public class FactoryBeanTest implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User("factory", "111111");
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
相应bean配置如下(注意,这里配置的类型为FactoryBeanTest):
<!--工厂bean-->
<bean id="factoryBean" class="di.pojo.FactoryBeanTest"/>
相应单元测试如下(注意,这里返回的类型为User)
@Test
public void demo7() {
User user = context.getBean("factoryBean", User.class);
System.out.println(user);
}
bean作用域
创建bean配置的对象是否为单例,默认为单例。
可以通过设置bean标签的scope,设置创建的对象是否为单例
prototype 非单例
singleton 单例
<bean id="user" class="di.pojo.User" scope="prototype"/>
bean生命周期
生命周期:
一个对象从创建到销毁的周期
bean的生命周期
1.调用构造方法构造对象
2.调用set方法设置属性
3.将对象传入后置处理器重写的postProcessBeforeInitialization方法
4.调用xml配置的初始化方法
5..将对象传入后置处理器重写的postProcessAfterInitialization方法
6.真正使用对象
7.销毁对象,通过ClassPathXmlApplicationContext的close方法销毁,销毁时会调用xml配置的注销方法
<!--演示bean的生命周期-->
<bean id="beanLifeCycle" class="di.pojo.lifecycle.BeanLifeCycle" init-method="init" destroy-method="destroy">
<property name="str" value="nothing"/>
</bean>
<!--配置后置处理器-->
<bean id="myPostProcessor" class="di.pojo.lifecycle.LifeOfPostProcessor"/>
后置处理器类
public class LifeOfPostProcessor implements BeanPostProcessor {
// 所有配置的bean都会调用这里
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第三步:调用初始化方法之前" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步:调用初始化方法之后" + beanName);
return bean;
}
}
基于注解管理bean
使用注解创建bean对象
@Component :通用标识bean对象的注解
@Service:标识业务层的bean对象的注解(Service层)
@Controller:标识控制器层的bean对象的注解(Web层)
@Repository:标识数据持久层的bean对象的注解(Dao层或者说Mapper层)
*这四个注解都可以标识一个bean,使其可以让IOC容器管理,但通常用不同的注解标识不同的层,更好区分。
// 默认值以类的首字母小写,相当于<bean id="components" class="di.component.Components"/>
@Component(value = "components")
public class Components {
public void simple(){
System.out.println("Components simple function");
}
}
使用注解注入属性
@Autowired 通过类型注入属性
@Qualifier 通过名称注入属性,必须和@Autowired配合使用
@Resource 通过类型或者名称注入属性,位于javax.annotation.Resource,并不属于spring框架
@Value 注入普通类型属性
例如:
@Service(value = "userService")
public class UserService {
@Autowired // 通过类型输入属性
@Qualifier("userImpl2") // 如果UserDao接口有多个实现类,就需要该注解通过名称注入属性了
private UserDao userDao;
@Value(value = "8080")
private String port;
// @Resource 位于javax.annotation.Resource,但是现在不见了。。。。
public void simple(){
System.out.println("UserService simple function");
}
public void userDaoMethod(){
System.out.println("port:" + port);
System.out.println("userDao.simple:");
userDao.simple();
}
}
当然仅仅是有注解还不行,spring并不知道哪些是需要管理的bean,所以需要配置,配置的方法有两种,一种是基于xml配置,一种是基于注解@Configuration配置。
基于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:contex="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">
<!--扫描ioc包下所有的注解-->
<contex:component-scan base-package="ioc">
</contex:component-scan>
</beans>
基于注解@Configuration配置
//完全注解开发,不依赖xml配置文件
@Configuration
@ComponentScan(basePackages = "ioc")
public class SpringConfig {
}