首先spring是一个企业级J2EE的框架,用于开发一个webApp,它是针对bean的生命周期进行管理的轻量级 容器 。主要由七个部分组成:Spring Core 、Spring AOP 、Spring ORM 、Spring DAO 、Spring Context 、Spring Web 、Spring Web MVC
它有 两大特性 : IOC 和 AOP 。
1.IOC容器是一个创建对象、配置对象、连接对象、并管理对象的生命周期的一个容器,这里的对象即bean对象。
2.bean 是一个被实例化,组装,并通过IOC容器所管理的对象。
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>
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标签的scope,设置创建的对象是否为单例
<bean id="user" class="di.pojo.User" scope="prototype"/>
一个对象从创建到销毁的周期
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; } }
@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 { }