Java实战之03Spring-02Spring的核心之IoC
二、Spring的核心之IoC(Inversion of Control 控制反转)
1、IoC是什么?
回顾:连接池原理中的使用。
注意:我们在连接池原理中是使用构造函数注入的,当然还可以通过提供set方法实现注入。
2、Spring容器
Spring容器简单理解就是用于存放对象的。
3、Spring的IoC入门
3.1、建立一个java工程
3.2、导入Spring的核心jar包
3.3、建立一个XML配置文件
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://www.springframework.org/schema/beans 4 http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 </beans>
注意:现在xml文件用什么名字无所谓。
关于spring的xml文件没有提示的原因和解决办法,与struts2和hibernate中相同。只是引入的约束前两个是dtd,而spring引入的schema约束。
3.4、资源交给Spring容器管理
1 <!-- 把持久层和业务层的创建都交给spring来管理 2 bean元素用于配置程序中可重用的组件。包括持久层,业务层以及表现层动作类 3 id属性指定的是spring容器中的key 4 class属性指定的就是类的全名称 5 spring容器在创建时,会读取配置文件,创建一个容器(map),把id作为key,把class属性创建的对象作为value,存入容器中 6 7 在加载配置文件时,会反射创建类对象。调用的默认无参的构造函数 8 --> 9 <bean id="userDao" class="cn.itcast.dao.impl.UserDaoForMySQLImpl"></bean> 10 11 <bean id="userService" class="cn.itcast.service.impl.UserServiceImpl"> 12 <!-- 在service中,注入dao --> 13 <property name="userDao" ref="userDao"></property> 14 </bean>
3.5、Spring容器的初始化及资源的获取
1 public static void main(String[] args) { 2 /* 3 * 1.加载配置文件,用于创建spring的容器(map) 4 * ClassPathXmlApplicationContext:表示配置文件在类路径下 5 * FileSystemXmlApplicationContext():当配置文件不在类路径下,而是在磁盘上时,使用此类加载。 6 */ 7 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); 8 //从容器中获取需要的对象:根据key取value 9 // IUserDao userDao = (IUserDao) ac.getBean("userDao"); 10 // System.out.println(userDao); 11 IUserService userService = (IUserService) ac.getBean("userService"); 12 System.out.println(userService); 13 userService.saveUser(); 14 }
4、Spring中API的体系结构
4.1、核心接口和类
BeanFactory:它使用的是延迟加载思想。当我们需要用bean时,才去创建对象。
ApplicationContext:它继承自BeanFactory接口,还继承了很多其他接口。功能比BeanFactory强大。它用的不是延迟加载思想,而是在加载配置文件时就创建了。(推荐)
FileSystemXmlApplicationContext:配置文件在本地磁盘上,使用该类加载。
ClassPathXmlApplicationContext :配置文件在classpath中,使用此类加载。
5、基于XML的spring的IoC配置
5.1、Spring实例化bean的方式
调用默认的构造方法 (推荐)
1 <!-- 把持久层和业务层的创建都交给spring来管理 2 bean元素用于配置程序中可重用的组件。包括持久层,业务层以及表现层动作类 3 id属性指定的是spring容器中的key 4 class属性指定的就是类的全名称 5 spring容器在创建时,会读取配置文件,创建一个容器(map),把id作为key,把class属性创建的对象作为value,存入容器中 6 7 需要掌握:在加载配置文件时,会反射创建类对象。调用的默认无参的构造函数。如果没有提供无参构造的情况下,是不能实例化bean对象的 8 --> 9 <bean id="userDao" class="cn.itcast.dao.impl.UserDaoForMySQLImpl"></bean> 10 11 <bean id="userService" class="cn.itcast.service.impl.UserServiceImpl"></bean>
5.2、Bean的作用范围
1 <!-- Bean的作用范围 2 scope属性: 3 取值: 4 singleton:单例(默认值) 5 prototype:多例 6 request:请求范围 7 session:会话范围 8 global-session:集群的会话范围。 9 --> 10 <bean id="userBean" class="cn.itcast.bean.UserBean1" scope="prototype"> 11 </bean>
5.3、Bean的生命周期方法
1 /** 2 * 模拟一个Bean 3 * @author zhy 4 * 5 */ 6 public class UserBean { 7 8 //实例化 9 public UserBean(){ 10 System.out.println("实例化:大爷来也!"); 11 } 12 //初始化 13 public void init(){ 14 System.out.println("初始化:大爷准备好了"); 15 } 16 //销毁 17 public void destroy(){ 18 System.out.println("销毁:老夫休矣!"); 19 } 20 21 public void saveUser(){ 22 System.out.println("业务方法:老夫只劫财不劫色"); 23 } 24 }
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://www.springframework.org/schema/beans 4 http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 <!-- Bean的生命周期 6 bean默认情况下是单例的,但是没有执行销毁方法。 7 bean:出生 活着 死亡 8 出生:在使用立即加载方式,spring容器一创建,bean对象就已经都创建好了。实例化bean和初始化bean就都执行了。 9 活着:spring容器还在,bean对象就一直在。 10 死亡:spring容器如果没了,bean对象也就消亡了。 11 --> 12 <bean id="userBean" class="cn.itcast.bean.UserBean" init-method="init" destroy-method="destroy"></bean> 13 </beans>
注意:当非单例时,初始化方法正常执行,但是销毁方法就不会执行了。
5.4、依赖注入
a、构造器注入:通过传参数
1 <!-- 第一种方式:是通过构造函数注入 2 使用construtor-arg 3 常用属性: 4 index:指定的是参数出现在构造函数中的索引 5 type:指定参数在构造函数中的数据类型 6 name:指定参数在构造函数中的名称 ***** 7 以上三个都是在指定:给谁注入 8 9 value:注入基本数据类型或者String类型的值 10 ref:注入的是其他bean类型的值 11 以上两个都是在指定:注入的值 12 13 当在定义bean时,使用了constructor-arg元素,则在bean元素中有几个constructor-arg,就需要提供对应参数列表的构造函数 14 --> 15 <bean id="userBean" class="cn.itcast.bean.UserBean1"> 16 <constructor-arg name="name" value="test" ></constructor-arg> 17 <constructor-arg name="age" value="18"></constructor-arg> 18 <constructor-arg name="birthday" ref="now" ></constructor-arg> 19 </bean>
b、属性注入:推荐
1 <!-- 第二种方式:是通过属性的set方法注入 2 需要使用的元素是:property 3 属性: 4 name:写的是set方法后面的部分,并且首字母转小写。 5 ref:注入的其他Bean类型的值 6 value:注入的是基本类型或者String类型的值 7 --> 8 <bean id="userBean2" class="cn.itcast.bean.UserBean2"> 9 <property name="name" value="test" ></property> 10 <property name="age" value="18"></property> 11 <property name="birthday" ref="now"></property> 12 </bean>
c、p名称空间
1 <beans xmlns="http://www.springframework.org/schema/beans" 2 xmlns:p="http://www.springframework.org/schema/p" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 <!-- 使用p名称空间注入 7 1、导入P名称空间:xmlns:p="http://www.springframework.org/schema/p" 8 2、在bean元素中使用p名称空间 9 p:属性名称。 10 属性名称指的是set方法后面的部分。 11 每个属性都有两个赋值方式: 12 p:属性名称 13 p:属性名称-ref 14 --> 15 <bean id="userBean4" class="cn.itcast.bean.UserBean4" p:name="test" p:age="20" p:birthday-ref="now"></bean> 16 17 <bean id="now" class="java.util.Date"></bean>
d、SpEL(Spring Expression Lanaguage)
1 <!-- 使用Spring中EL表达式。SpringEL 目前定位:了解 2 ${now}就是SPring的EL表达式 3 --> 4 <bean id="userBean3" class="cn.itcast.bean.UserBean3"> 5 <property name="name" value="test" ></property> 6 <property name="age" value="18"></property> 7 <property name="birthday" value="#{now}"></property> 8 </bean>
e、注入集合数据
1 <!-- 注入集合数据 2 如果是对象集合数据,list结构的,可以使用如下三个元素: 3 array 4 list 5 set 6 如果是map结构的,可以使用如下四个元素 7 map: 8 map的子元素是entry 9 props 10 props的子元素是prop 11 只要结构相同,元素可以互换。 12 --> 13 <bean id="userBean5" class="cn.itcast.bean.UserBean5"> 14 <!-- 给数组注入值 --> 15 <property name="myStrs"> 16 <list> 17 <value>AAA</value> 18 <value>BBB</value> 19 <value>CCC</value> 20 </list> 21 </property> 22 <!-- 给List集合注入值 --> 23 <property name="myList"> 24 <set> 25 <value>AAA</value> 26 <value>BBB</value> 27 <value>CCC</value> 28 </set> 29 </property> 30 <!-- 给Set集合注入值 --> 31 <property name="mySet"> 32 <array> 33 <value>AAA</value> 34 <value>BBB</value> 35 <value>CCC</value> 36 </array> 37 </property> 38 <!-- 给map注入数据 --> 39 <property name="myMap"> 40 <props> 41 <prop key="testA">AAA</prop> 42 <prop key="testB">BBB</prop> 43 <prop key="testC">CCC</prop> 44 </props> 45 </property> 46 <!-- 给properties注入数据 --> 47 <property name="myProps"> 48 <map> 49 <entry key="AAA"> 50 <value>testA</value> 51 </entry> 52 <entry key="BBB" value="testB"></entry> 53 <entry key="CCC"> 54 <value>testC</value> 55 </entry> 56 </map> 57 </property>
5.5、团队开发:多个Spring配置文件
a、一次加载多个配置文件
1 public static void main(String[] args) { 2 ApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml"); 3 //获取bean对象 4 UserBean1 bean1 = (UserBean1)ac.getBean("userBean1"); 5 bean1.saveUser(); 6 7 UserBean2 bean2 = (UserBean2)ac.getBean("userBean2"); 8 bean2.saveUser(); 9 }
b、基于主从配置文件
1 <!-- Spring的多配置文件 2 引入其他的配置 3 --> 4 <import resource="bean1.xml"/> 5 <import resource="bean2.xml"/>
c、注意事项
同一个配置文件中不能出现bean元素id属性取值相同的:
不同文件中bean元素id属性取值相同时,有加载顺序
使用bean的name属性获取bean对象(了解就行)
6、基于注解的spring的IoC配置
6.1、注解的使用前提
a、引入context的名称空间
b、指定要扫描的包
c、在Bean上面加入@Component注解
1 @Component("userBean") 2 //就相当于在配置文件中配置<bean id="userBean" class="cn.itcast.bean.UserBean" /> 3 public class UserBean { 4 5 @Value(value="test") 6 private String name; 7 8 public void saveUser(){ 9 System.out.println("业务方法:老夫只劫财不劫色"); 10 System.out.println(name); 11 } 12 }
b、@Component的衍生注解@Controller@Service@Repository
作用:和@Component作用一样,让Spring容器管理(实例化)当前的bean。
属性: value:指定bean的名称。默认值是当前类的简单类名首字母小写
特点:在三成架构中,每个注解对应一层,使语义更加明确。
@Controller:一般用在表现层,比如struts2的action上
@Service:一般用在业务层,比如Service实现
@Repository:一般用在持久层,比如Dao实现
1 @Repository("userDaoForMySQL") 2 public class UserDaoForMySQLImpl implements IUserDao { 3 4 5 public void saveUser() { 6 System.out.println("MySQL:保存了用户"); 7 } 8 9 public void deleteUser() { 10 System.out.println("MySQL:删除了用户"); 11 } 12 13 } 14 @Service("userService") 15 public class UserServiceImpl implements IUserService { 16 17 public void saveUser() { 18 System.out.println("UserServiceImpl的savaUser方法执行了"); 19 userDao.saveUser(); 20 } 21 22 public void deleteUser() { 23 userDao.deleteUser(); 24 } 25 26 } 27 @Controller("userAction") 28 public class UserAction { 29 30 public String saveUser(){ 31 System.out.println("UserAction的savaUser方法执行了"); 32 userService.saveUser(); 33 return null; 34 } 35 }
c、@Autowired
作用:自动按类型注入需要的对象。当使用了该注解时,setter就不是必须的了。
属性:
required:是否必须注入成功。默认值是true。
true:必须注入成功,如果出现注入失败,抛出异常。
false:不一定注入成功,不抛异常。
注意事项:
一个Service接口:IBookService
两个Service实现:BookServiceImpl1 BookServiceImpl2
由于@Autowired是自动按类型注入,当使用接口类型时,就看变量的名称,如果变量名称是bookServiceImpl1,则使用BookServiceImp1这个实现类,
如果变量名是bookServiceImpl2,则使用BookServiceImpl2这个实现类。如果没有符合规范的名称(类名首字母小写),则报错。
到底注入哪个实现类:
@Autowried
private BookService bookServiceImpl1;//注入BookServiceImpl1
@Autowried
private BookService bookServiceImpl2;//注入BookServiceImpl2
@Autowried
private BookService bookService;//注入失败
d、@Value
作用:注入基本类型和String。
属性:value:SpEL表达式,要注入的值
e、@Qualifier
作用:要配合@Autowried来一起使用,通过它指定要注入的bean的名称。按类型注入失效了。
属性:value:要注入的bean的名称
f、@Resource
作用:如同@Autowire和@Qualifier,是规范JSR-250中定义的(JCP)。通过指定bean的名称注入对象。
属性: name:要注入的bean的名称
g、@PostConstruct(了解)
作用:用在初始化方法上。生命周期有关
h、@PreDestroy(了解)
作用:用在销毁方法上。生命周期有关
i、@Configuration和@Bean(了解)
作用:@Configuration指定当前类为配置类,用于加载@Bean的定义。@Bean用于定义bean的名称,用法是@Bean(name="beanName")
注意:该类要被设置在注解自动扫描对应的包下。
6.3、Spring中使用单元测试
a、导入jar包:
spring-test-3.2.0.RELEASE.jar
b、设置Junit运行器和Spring配置文件
1 /** 2 * Spring整合Junit 3 * 1、导入junit的jar包。导入spring整合junit的jar包 4 * 2、要替换运行器(其实就是测试用的main函数),换成spring框架提供的,因为只有spring框架提供的才能支持spring。 5 * 3、告知新运行器,spring的配置文件所在的位置 6 * @author zhy 7 * 8 */ 9 @RunWith(SpringJUnit4ClassRunner.class) 10 @ContextConfiguration(locations={"classpath:bean.xml"}) 11 public class UserBeanTest { 12 13 @Autowired 14 private UserBean userBean; 15 16 @Test 17 public void testSaveUser(){ 18 userBean.saveUser(); 19 } 20 }