文章目录
一、Spring是什么?
spring是一个开源的控制反转(Ioc)和面向切面(Aop)的容器框架
其优点:
(1)方便解耦,简化开发,实现软件各层之间的解耦
(2)方便集成各种优秀的框架,如:集成Hibernate、JPA、Struts2等,这样更便于应用的开发。
(3)降低javaEE的API的使用难度,容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
(4)方便程序的测试,容器提供单例模式支持,开发人员不再需要自己编写实现代码。
(5)AOP编程的测试,利用它很容易实现如权限拦截、运行期监控等功能。
(6)声明式事物的支持,可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务,也不需处理复杂的事务传播
引入一个控制反转的实例进行解释
二、Spring的控制反转(Ioc)
1.什么是控制反转
(1) 定义:是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的。这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转。
(2)引入一个控制反转的实例进行解释
比如我们写了一个接口,两个接口实现类,定义了一个服务类去处理使用接口中的两个实现类方法。在不改变原有代码的基础上,能够按照调用者自己的选择,去调用哪个接口的实现类,完全取决于调用者-----这就用到了依赖注入(DI)实现原理
代码如下(示例):
接口类
public interface StudentDao {
public void delete();
}
两个接口实现类
public class StudentDaoImplMysql implements StudentDao{
@Override
public void delete() {
System.out.println("使用mysql数据库删除数据");
}
}
public class StudentDaoImplOracle implements StudentDao{
@Override
public void delete() {
System.out.println("使用oracle数据库删除数据");
}
}
业务处理服务类
public class StudentService {
private StudentDao studentDao;
public StudentService(StudentDao studentDao){
this.studentDao = studentDao;
}
public void delete(){
studentDao.delete();
}
}
调用者测试类
public class Test {
public static void main(String[] args) {
StudentService service = new StudentService(new StudentDaoImplOracle());
service.delete();
}
}
2.什么是依赖注入
(1)定义:在运行期,由外部容器动态地将依赖对象注入到组件中(spring容器在创建被调用者的实例时,会自动将调用者需要的对象注入给调用者----调用者通过spring容器获得被调用者实例)
(2)springIoc依赖注入的两种方式:
- 属性set方式注入
业务层接口类引入数据处理层类接口,并使用数据处理接口类中的实现类中的方法
业务层接口实现类中调用外部接口类关键代码
public class PersonServiceImpl implements PersonService {
// 定义接口声明
private PersonDao personDao;
// 提供set()方法,用于依赖注入
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
} // 实现PersonService接口的方法
@Override
public void addPerson() {
personDao.add(); // 调用PersonDao中的add()方法
System.out.println("addPerson()执行了...");
}
}
配置xml文件中的配置,被依赖者依赖被依赖者中,调用者中把被调用者引用属性进行连接,通过ref=""这个属性,而不是value=””这个属性建立依赖
<bean id="personService" class="com.mengma.ioc.PersonServiceImpl">
<!-- 将personDao实例注入personService实例中 -->
<property name="personDao" ref="personDao"/>
</bean>
- 构造方法方式注入
业务层接口实现类中调用外部接口类关键代码
public class PersonServiceImpl implements PersonService {
// 定义接口声明
private PersonDao personDao;
// 提供set()方法,用于依赖注入
public PersonServiceImpl(PersonDao personDao) {
this.personDao = personDao;
} // 实现PersonService接口的方法
@Override
public void addPerson() {
personDao.add(); // 调用PersonDao中的add()方法
System.out.println("addPerson()执行了...");
}
}
3.springIoc容器的使用
(1)使用springIoc容器,这采用配置文件xml来进行对bean对象的创建和管理:applicationContext.xml文件就是spring容器,把需要该容器创建对象的类通过bean标签配置在此即可,默认是加载该文件时创建对象,每一个类只创建一个对象。
相关一些bean标签的属性以及属性值的简单介绍
- id=“student” ,获取对象名称
- class=“com.entor.entity.Student”,类名,容器会根据全类名路径字符串反射创建对象
- lazy-init=“true”,延迟创建对象,在使用该对象时才创建并初始化,可缩短spring容器启动时间,节省内存空间
- scope=“prototype”,每次调用都创建新的对象,默认是singleton单例
- init-method=“init” ,对象初始化方法,只执行一次
- destroy-method=“destroy”,对象销毁时调用的方法,只执行一次
(2)对于基本数据类型bean类,使用springIoc来管理
(一)主要是以在配置文件中的bean标签配置对象的创建和初始化
(1) Bean类代码
public class Bean {
private Integer intValue;
private String strValue;
private String[] arrayValue;
private List<String> listValue;
private Set<String> setValue;
private Map<String,String> mapValue;
private Properties propValue;
public Bean() {
}
public Bean(Integer intValue, String strValue, String[] arrayValue, List<String> listValue, Set<String> setValue, Map<String, String> mapValue, Properties propValue) {
this.intValue = intValue;
this.strValue = strValue;
this.arrayValue = arrayValue;
this.listValue = listValue;
this.setValue = setValue;
this.mapValue = mapValue;
this.propValue = propValue;
}
public Integer getIntValue() {
return intValue;
}
public void setIntValue(Integer intValue) {
this.intValue = intValue;
}
public String getStrValue() {
return strValue;
}
public void setStrValue(String strValue) {
this.strValue = strValue;
}
public String[] getArrayValue() {
return arrayValue;
}
public void setArrayValue(String[] arrayValue) {
this.arrayValue = arrayValue;
}
public List<String> getListValue() {
return listValue;
}
public void setListValue(List<String> listValue) {
this.listValue = listValue;
}
public Set<String> getSetValue() {
return setValue;
}
public void setSetValue(Set<String> setValue) {
this.setValue = setValue;
}
public Map<String, String> getMapValue() {
return mapValue;
}
public void setMapValue(Map<String, String> mapValue) {
this.mapValue = mapValue;
}
public Properties getPropValue() {
return propValue;
}
public void setPropValue(Properties propValue) {
this.propValue = propValue;
}
@Override
public String toString() {
return "Bean{" +
"intValue=" + intValue +
", strValue='" + strValue + '\'' +
", arrayValue=" + Arrays.toString(arrayValue) +
", listValue=" + listValue +
", setValue=" + setValue +
", mapValue=" + mapValue +
", propValue=" + propValue +
'}';
}
}
(2)配置文件进行对bean各属性赋值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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="bean" class="com.entor.entity.Bean">
<property name="intValue" value="1"/>
<property name="strValue" value="张三"/>
<property name="arrayValue">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
<property name="listValue">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
<property name="setValue">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</set>
</property>
<property name="mapValue">
<map>
<entry key="CN" value="中国"/>
<entry key="EN" value="美国"/>
<entry key="JP" value="日本"/>
</map>
</property>
<property name="propValue">
<props>
<prop key="CN">中国</prop>
<prop key="EN">美国</prop>
<prop key="JP">日本</prop>
</props>
</property>
</bean>
</beans>
(3)Student类对象代码
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
System.out.println("Student类对象创建");
}
public Student(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public void init(){
System.out.println("Student对象初始化");
}
public void destroy(){
System.out.println("Student对象销毁");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
(4) 归纳xml对bean对象属性赋值
- 基本数据类型直接赋值
<property name="intValue" value="1"/>
<property name="strValue" value="张三"/>
- 数组类型赋值
<property name="arrayValue">
<array>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</array>
</property>
- list集合类型赋值
<property name="listValue">
<list>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</list>
</property>
- set集合类型赋值
<property name="setValue">
<set>
<value>张三</value>
<value>李四</value>
<value>王五</value>
</set>
</property>
- map集合类型赋值
<property name="mapValue">
<map>
<entry key="CN" value="中国"/>
<entry key="EN" value="美国"/>
<entry key="JP" value="日本"/>
</map>
</property>
- 配置文件properties赋值
<property name="propValue">
<props>
<prop key="CN">中国</prop>
<prop key="EN">美国</prop>
<prop key="JP">日本</prop>
</props>
</property>
(5)配置文件进行对Student类各属性赋值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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="student"
class="com.entor.entity.Student"
lazy-init="true"
scope="prototype"
init-method="init"
destroy-method="destroy">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="20"/>
</bean>
</beans>
(6)加载xml配置文件测试类
public class Test {
public static void main(String[] args) {
/*
//用户自己创建对象
Student s = new Student();
s.setId(1);
s.setName("张三");
s.setAge(20);
System.out.println(s);
*/
//把对象创建的工作交给spring容器集中创建,要用的时候直接去spring容器中去拿
//1、加载spring配置文件,启动spring容器,创建对象,每一个类默认单例模式创建,默认在加载文件时创建
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、从spring容器中获取对象
Student student = (Student)context.getBean("student");
Student s = context.getBean(Student.class);
//3、使用对象
System.out.println(student);
System.out.println(s);
System.out.println(s==student);
//当true,当 scope="singleton"单例模式时;当false,当 scope="prototype",每次调用都创建新的对象
Bean bean = (Bean) context.getBean("bean");
System.out.println(bean);
System.out.println("intValue:"+bean.getIntValue());
System.out.println("strValue:"+bean.getStrValue());
System.out.println("arrayValue:"+bean.getArrayValue());
System.out.println("listValue:"+bean.getListValue());
System.out.println("setValue:"+bean.getSetValue());
System.out.println("mapValue:"+bean.getMapValue());
System.out.println("propValue:"+bean.getPropValue());
}
}
(二)主要是以注解形式实现bean对象的Ioc管理
需要在xml文件中添加自动扫描标签
- 开启注解模式,这样就可以使用@ Resource 、@ PostConstruct、@ PreDestroy、@PersistenceContext、@Autowired、@Required等注解了,就可以实现自动注入
<context:annotation-config/>
- 组件包扫描,指定包路径下的所有被注解@Component标识过的类,创建对象,除了具有context:annotation-config的功能之外,context:component-scan还可以在指定的package下扫描以及注册javabean
<context:component-scan base-package="com.entity"/>
- 导入其他的配置文件,按照导入文件顺序加载,默认根据配置bean的先后顺序创建对象
<import resource="applicationContext.xml"/>
- 等同于上面的引入外部的xml文件,就是在加载配置文件路径时,其中applicationContext*.xml"中的*是改配置文件下的所有配置文件,但是不知道顺序,先后不确定
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
三、springIoc容器的依赖注入
对象之间的相互依赖注入
(1)xml配置实体类Bean1依赖于Bean2和Bean3实体类
- set方法注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean1" class="com.entity.Bean1">
<property name="bean2" ref="bean2"/>
<property name="bean3" ref="bean3"/>
<!--对象之间引用关系要用ref修饰-->
</bean>
</beans>
- 构造方法注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean1" class="com.entity.Bean1">
<constructor-arg index="0" ref="bean2"/>
<!--通过index位置指定构造方法参数传入的顺序,如果不指定,就是默认的按照参数传入顺序,不能错乱顺序-->
<constructor-arg index="1" ref="bean3"/>
</bean>
</beans>
- Bean1关联的Bean2和Bean3的实体类
public class Bean1 {
/**
* @Resource作用在属性上,默认根据属性名称去配置文件中查找对应的bean,
* 创建对象后赋值给该属性变量,如果找不到,则根据属性类型去查找bean,
* 如果再找不到或者有多个值报错
*
* 注解可以指定name属性,则根据指定的名称去配置文件查找,
* 一旦指定了名称,则会根据指定的名称查找,如果找不到则报错
*
* @Autowired:作用在属性上,默认根据属性类型去配置文件查找对应的bean,创建对象后赋值给该属性变量
* 如果找不到或者找到多个,则根据属性名称去查找bean,如果找不到则会报错
* @Qualifier(value = "a")指定name属性名称查找bean,这个配合 @Autowired,如果找不到就会报错
*
* 总结:两个注解都是作用在属性上,set、get方法可省略
*/
// @Resource/*指定ID属性值查找*/
//@Autowired
//@Qualifier(value = "bean2")
private Bean2 bean2;
/*@Resource*/
// @Autowired
private Bean3 bean3;
public Bean1() {
}
public Bean2 getBean2() {
return bean2;
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean3 getBean3() {
return bean3;
}
public void setBean3(Bean3 bean3) {
this.bean3 = bean3;
}
public Bean1(Bean2 bean2, Bean3 bean3) {
this.bean2 = bean2;
this.bean3 = bean3;
}
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
'}';
}
}
//外部实体类
//@Component
public class Bean2 {
}
//@Component
public class Bean3 {
}
- 测试类
public class Test1 {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
/*"applicationContext*.xml"中的*是改配置文件下的所有配置文件,但是不知道顺序,先后不确定*/
/* ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
* 与application配置文件中的 <import resource="applicationContext.xml"/>是一样的,但这个有先后顺序
*
* */
Bean bean=context.getBean(Bean.class);
Bean1 bean1=context.getBean(Bean1.class);
//Bean2 bean2=context.getBean(Bean2.class);
Bean2 bean22=(Bean2) context.getBean("bean2");
/* Bean2 bean2=( Bean2 )context.getBean("bean2");*/
// Bean2 bean22=( Bean2 )context.getBean("bean33");
Bean2 bean2=context.getBean(Bean2.class);
Bean3 bean3=context.getBean(Bean3.class);
/* Bean3 bean3=(Bean3)context.getBean("bean33");*/
System.out.println("bean = " + bean);
System.out.println("bean1 = " + bean1);
System.out.println("bean2 = " + bean2);
System.out.println("bean22 = " + bean22);
/* System.out.println("bean22 = " + bean22);
System.out.println(bean2==bean22);*/
System.out.println("bean3 = " + bean3);
}
}
(2)注解配置实体类Bean1依赖于Bean2和Bean3实体类
- xml开启注解标签模式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--组件包扫描,指定包路径下的所有被注解@Component标识过的类,创建对象,除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean-->
<context:component-scan base-package="com.entity"/>
<!--开启注解模式--><!--这样就可以使用@ Resource 、@ PostConstruct、@ PreDestroy、@PersistenceContext、@Autowired、@Required等注解了,就可以实现自动注入-->
<!-- <context:annotation-config/>-->
<import resource="applicationContext.xml"/>
<!--导入其他的配置文件,按照导入文件顺序加载,默认根据配置bean的先后顺序创建对象-->
</beans>
- Bean1依赖Bean2和Bean3实体类
//Bean1实体类
@Component(value = "bean1")
public class Bean1 {
/**
* @Resource作用在属性上,默认根据属性名称去配置文件中查找对应的bean,
* 创建对象后赋值给该属性变量,如果找不到,则根据属性类型去查找bean,
* 如果再找不到或者有多个值报错
*
* 注解可以指定name属性,则根据指定的名称去配置文件查找,
* 一旦指定了名称,则会根据指定的名称查找,如果找不到则报错
*
* @Autowired:作用在属性上,默认根据属性类型去配置文件查找对应的bean,创建对象后赋值给该属性变量
* 如果找不到或者找到多个,则根据属性名称去查找bean,如果找不到则会报错
* @Qualifier(value = "a")指定name属性名称查找bean,这个配合 @Autowired,如果找不到就会报错
*
* 总结:两个注解都是作用在属性上,set、get方法可省略
*/
// @Resource/*指定ID属性值查找*/
@Autowired
//@Qualifier(value = "bean2")
private Bean2 bean2;
/*@Resource*/
@Autowired
private Bean3 bean3;
@Override
public String toString() {
return "Bean1{" +
"bean2=" + bean2 +
", bean3=" + bean3 +
'}';
}
}
//Bean2实体类
@Component
public class Bean2 {
}
//Bean3实体类
@Component
public class Bean3 {
}
- 测试类
public class Test1 {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
/*"applicationContext*.xml"中的*是改配置文件下的所有配置文件,但是不知道顺序,先后不确定*/
/* ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
* 与application配置文件中的 <import resource="applicationContext.xml"/>是一样的,但这个有先后顺序
*
* */
Bean bean=context.getBean(Bean.class);
Bean1 bean1=context.getBean(Bean1.class);
//Bean2 bean2=context.getBean(Bean2.class);
//Bean2 bean2=(Bean2) context.getBean("bean2");
/* Bean2 bean2=( Bean2 )context.getBean("bean2");*/
// Bean2 bean22=( Bean2 )context.getBean("bean33");
Bean2 bean2=context.getBean(Bean2.class);
Bean3 bean3=context.getBean(Bean3.class);
/* Bean3 bean3=(Bean3)context.getBean("bean33");*/
System.out.println("bean = " + bean);
System.out.println("bean1 = " + bean1);
System.out.println("bean2 = " + bean2);
/* System.out.println("bean22 = " + bean22);
System.out.println(bean2==bean22);*/
System.out.println("bean3 = " + bean3);
}
}
springIoc容器获取bean对象两种方式
通过属性名称id来获取
- xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean2" class="com.entity.Bean2"/>
<bean id="bean22" class="com.entity.Bean2"/>
<bean id="bean3" class="com.entity.Bean3"/>
<bean id="bean33" class="com.entity.Bean3"/>
</beans>
- 测试类
public class Test1 {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
/*"applicationContext*.xml"中的*是改配置文件下的所有配置文件,但是不知道顺序,先后不确定*/
/* ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
* 与application配置文件中的 <import resource="applicationContext.xml"/>是一样的,但这个有先后顺序
*
* */
Bean bean=context.getBean(Bean.class);
Bean1 bean1=context.getBean(Bean1.class);
// Bean1 bean11=(Bean1) context.getBean("bean1");
// Bean2 bean2=context.getBean(Bean2.class);
Bean2 bean22=(Bean2) context.getBean("bean22");
Bean2 bean2=( Bean2 )context.getBean("bean2");
// Bean2 bean22=( Bean2 )context.getBean("bean33");
// Bean2 bean2=context.getBean(Bean2.class);
//Bean3 bean3=context.getBean(Bean3.class);
/* Bean3 bean3=(Bean3)context.getBean("bean33");*/
System.out.println("bean = " + bean);
System.out.println("bean1 = " + bean1);
// System.out.println("bean11 = " + bean11);
System.out.println("bean2 = " + bean2);
System.out.println("bean22 = " + bean22);
/* System.out.println("bean22 = " + bean22);
System.out.println(bean2==bean22);*/
// System.out.println("bean3 = " + bean3);
}
}
通过属性类型全限定类名获取
- xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean2" class="com.entity.Bean2"/>
<bean id="bean22" class="com.entity.Bean2"/>
<bean id="bean3" class="com.entity.Bean3"/>
<bean id="bean33" class="com.entity.Bean3"/>
</beans>
- 测试类------这时会报一个错误(No qualifying bean of type ‘com.entity.Bean2’ available: expected single matching bean but found 2: bean2,bean22),这就是getBean方法(运行时类名获取)限制,一旦定下bean的类型class,就是唯一性,不能存在另外一个同一个类型的bean
public class Test1 {
public static void main(String[] args) {
// ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-bean.xml");
/*"applicationContext*.xml"中的*是改配置文件下的所有配置文件,但是不知道顺序,先后不确定*/
/* ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext*.xml");
* 与application配置文件中的 <import resource="applicationContext.xml"/>是一样的,但这个有先后顺序
*
* */
Bean bean=context.getBean(Bean.class);
Bean1 bean1=context.getBean(Bean1.class);
// Bean1 bean11=(Bean1) context.getBean("bean1");
Bean2 bean2=context.getBean(Bean2.class);
//Bean2 bean22=(Bean2) context.getBean("bean22");
/* Bean2 bean2=( Bean2 )context.getBean("bean2");*/
// Bean2 bean22=( Bean2 )context.getBean("bean33");
// Bean2 bean2=context.getBean(Bean2.class);
Bean3 bean3=context.getBean(Bean3.class);
/* Bean3 bean3=(Bean3)context.getBean("bean33");*/
System.out.println("bean = " + bean);
System.out.println("bean1 = " + bean1);
// System.out.println("bean11 = " + bean11);
//System.out.println("bean2 = " + bean2);
// System.out.println("bean22 = " + bean22);
/* System.out.println("bean22 = " + bean22);
System.out.println(bean2==bean22);*/
System.out.println("bean3 = " + bean3);
}
}
xml配置文件中bean的id属性名称相同,属性类型不同,通过springIoc加载配置文件时会报错(Configuration problem: Bean name ‘bean33’ is already used in this element
Offending resource: class path resource [applicationContext-bean.xml]
)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="bean2" class="com.entity.Bean2"/>
<bean id="bean33" class="com.entity.Bean2"/>
<bean id="bean3" class="com.entity.Bean3"/>
<bean id="bean33" class="com.entity.Bean3"/>
</beans>
xml配置文件注入集合对象(一对多的形式)
<!--一个班级对象对应多个学生的集合类型的创建,给bean注入集合-->
<bean id="classes" class="com.entity.Classes">
<property name="classNo" value="1001"/>
<property name="className" value="计本"/>
<property name="students">
<list>
<ref bean="student1"/>
<ref bean="student2"/>
</list>
</property>
</bean>
<bean id="student1" class="com.entity.Student">
<property name="id" value="1"/>
<property name="name" value="张三1"/>
<property name="age" value="22"/>
</bean>
<bean id="student2" class="com.entity.Student">
<property name="id" value="2"/>
<property name="name" value="张三2"/>
<property name="age" value="24"/>
</bean>
scope作用域
spring管理的bean是根据scope来生成的,表示bean的作用域,共4中,默认是singleton(单例模式)
- singleton:单例模式,表示通过Ioc容器获取的bean是唯一的
- prototype:原型模式,表示通过Ioc容器获取的bean是不同的(不唯一)
- request:请求,表示在一次http请求内有效
- session:会话,表示在一个用户会话内有效
- request和session只适用于Web项目,大多数情况下,使用的是单例和原型模式较多
- prototype模式当业务代码获取Ioc容器中的bean时,spring才去调用无参构造创建对应的bean
- singleton模式无论业务代码是否获取Ioc容器中的bean,spring在加载spring的xml配置文件时就会已经创建该bean了
spring对象之间的继承关系
这个是与java的单继承不同的是,java是类层面的继承关系,子类可以继承父类的内部结构信息;spring是对象层面的继承关系,子对象可以继承父对象的属性值
spring继承的关注点是在具体的对象,而不再具体的类,也就是不同的两个类的实例化对象可以完成继承,前提条件是子对象必须包含父对象的所有属性,同时可以在此基础上添加其他属性
- 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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">
<!--所有类都创建,在xsi标签后面添加scope="prototype"-->
<bean id="student" class="com.entity.Student" scope="singleton">
<property name="id" value="2"/>
<property name="name" value="张三2"/>
<property name="age" value="22"/>
</bean>
<!-- <bean id="stu" class="com.entity.Student" parent="student">-->
<!-- <property name="id" value="10"></property>-->
<!-- <property name="name" value="王五"/>-->
<!-- <property name="age" value="102"/>-->
<!-- </bean>-->
<bean id="user" class="com.entity.User" parent="student">
<property name="sex" value="男"/>
</bean>
</beans>
- 实体类(User 类继承Student类)
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
}
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String sex;
}
- 测试类
public class Test4 {
public static void main(String[] args) {
/* System.out.println("你好");这是用户自己创建对象
Student s=new Student();
s.setId(1);
s.setName("张三");
s.setAge(20);
System.out.println("s = " + s);*/
//把对象创建的工作交给spring容器集中创建,要用的时候直接去spring容器中去拿
//1、加载spring配置文件,启动spring容器,创建对象,每一个类默认是单例模式创建对象
//默认在加载文件时创建
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
/*ClassPathXmlApplicationContext()---->src下的类路径*/
//2、从spring容器中获取对象
Student student = (Student)context.getBean("student");
System.out.println("student="+student);
//3、使用对象
System.out.println("===========");
// Student stu =(Student) context.getBean("stu");
// System.out.println("stu = " + stu);
User user =(User) context.getBean("user");
System.out.println("user = " + user);
}
}
springIoc容器的依赖bean属性(depends-on)
与继承关系类似的,依赖也是描述bean与bean之间的一种关系,配置依赖之后,被依赖的bean一定先创建,在创建依赖的bean。譬如A依赖于B,那么先创建B,然后再创建A(在没有引入depends-on这个属性时,在xml配置文件中按照bean标签的顺序依次创建bean,那么在加载获取bean对象顺序创建时,得到的对象顺序是按照xml配置文件顺序获取的,跟加载获取bean对象的顺序无关)
- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--所有类都创建,在xsi标签后面添加scope="prototype"-->
<bean id="classes" class="com.entity.Classes" depends-on="student">
<property name="classNo" value="1"/>
<property name="className" value="计本"/>
<property name="students">
<list>
<ref bean="student"/>
<!-- <ref bean="student1"/>-->
</list>
</property>
</bean>
<bean id="student" class="com.entity.Student">
<property name="id" value="1"/>
<property name="name" value="王五"/>
<property name="age" value="25"/>
</bean>
</beans>
- 实体类(Classes类依赖于Student类)
@Data
public class Classes {
private Integer classNo;
private String className;
private List<Student> students;
public Classes(){
System.out.println("classes对象创建");
}
}
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
System.out.println("Student类对象创建");
}
}
- 测试类
public class Test5 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
Classes classes =(Classes) context.getBean("classes");
System.out.println("classes = " + classes);
Student student =(Student) context.getBean("student");
System.out.println("student = " + student);
// Classes classes =(Classes) context.getBean("classes");
// System.out.println("classes = " + classes);
}
}
Spring的p命名空间
p的命名空间是对Ioc/DI的简化操作,使用怕p命名空间可以更加方便的完成bean的配置以及bean之间的依赖注入
- 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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--所有类都创建,在xsi标签后面添加scope="prototype"-->
<bean id="classes" class="com.entity.Classes" p:classNo="1" p:className="数学" p:students-ref="student">
</bean>
<bean id="student" class="com.entity.Student" p:id="2" p:name="刘邦" p:age="20"/>
<!-- <bean id="classes" class="com.entity.Classes" depends-on="student">-->
<!-- <property name="classNo" value="1"/>-->
<!-- <property name="className" value="计本"/>-->
<!-- <property name="students">-->
<!-- <list>-->
<!-- <ref bean="student"/>-->
<!--<!– <ref bean="student1"/>–>-->
<!-- </list>-->
<!-- </property>-->
<!-- </bean>-->
<!-- <bean id="student" class="com.entity.Student">-->
<!-- <property name="id" value="1"/>-->
<!-- <property name="name" value="王五"/>-->
<!-- <property name="age" value="25"/>-->
<!-- </bean>-->
</beans>
- 实体类(Classes类依赖于Student类)
@Data
public class Student {
private Integer id;
private String name;
private Integer age;
public Student() {
System.out.println("Student类对象创建");
}
}
@Data
public class Classes {
private Integer classNo;
private String className;
private List<Student> students;
public Classes(){
System.out.println("classes对象创建");
}
}
- 测试类
public class Test6 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml");
Classes classes =(Classes) context.getBean("classes");
System.out.println("classes = " + classes);
Student student =(Student) context.getBean("student");
System.out.println("student = " + student);
// Classes classes =(Classes) context.getBean("classes");
// System.out.println("classes = " + classes);
}
}
四、springIoc容器的工厂方法
Ioc通过工厂模式创建bean的两种方式
静态工厂方法
- 实体类----工厂类(在此类中注入Car实体类)
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private Integer id;
private String name;
}
public class StaticFactory {
private static Map<Integer, Car> map;
static {
map=new HashMap<>();
map.put(1,new Car(1,"宝马"));
map.put(2,new Car(2,"奔驰"));
}
public static Car getCar(Integer id){
return map.get(id);
}
}
- 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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置静态工厂创建bean-->
<bean id="car" class="com.cn.staticcarfactory.StaticFactory" factory-method="getCar">
<constructor-arg value="1"/>
</bean>
</beans>
- 测试类
import com.entity.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-factory.xml");
Car car = (Car)context.getBean("car");
System.out.println("car = " + car);
}
}
实例工厂方法
- 实体类-----工厂类(在此类中注入Car实体类)
@Data
public class User {
private Integer id;
private String name;
private Integer age;
private String sex;
private User(){
System.out.println("User对象创建");
}
}
public class InstanceFactory {
private Map<Integer, Car> map;
// static {
// map=new HashMap<>();
// map.put(1,new Car(1,"宝马"));
// map.put(2,new Car(2,"奔驰"));
// }
public InstanceFactory(){
System.out.println("InstanceFactory对象创建");
map=new HashMap<>();
map.put(1,new Car(1,"比亚迪"));
map.put(2,new Car(2,"红旗"));
}
public Car getCar(Integer id){
return map.get(id);
}
// public Car createBean(){
// return new Car();
// }
// public Car createBean1(){
// return new Car();
// }
}
- 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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置实例工厂创建bean-->
<bean id="myfactory" class="com.cn.carfactory.InstanceFactory">
</bean>
<bean id="car" factory-bean="myfactory" factory-method="getCar">
<constructor-arg value="2"/>
</bean>
<!-- <bean id="car1" factory-bean="myfactory" factory-method="getCar">-->
<!-- <constructor-arg value="2"/>-->
<!-- </bean>-->
</beans>
- 测试类
public class InstanceTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-instancefactory1.xml");
Car car = (Car)context.getBean("car");
System.out.println("car = " + car);
//自己new一个实例对象
// InstanceFactory instanceFactory = new InstanceFactory();
// Car car = instanceFactory.getCar(3);
// System.out.println("car = " + car);
}
}
Ioc自动装载(Autowire)
Ioc负责创建对象,DI负责完成对象的依赖注入,通过配置property标签的ref属性来完成,同时spring还提供了一种另外更加简便的依赖注入方式:自动装载,不需要手动添加配置property,Ioc容器会自动选择bean完成注入工作
自动装载有两种方式
- byName属性:通过属性名自动装载
示例
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private Integer id;
private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Integer id;
private String name;
private Car car;
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--这里的car类型bean中的id值对应上person实体类中的成员变量名,否则通过byName自动装配会失败-->
<bean id="car" class="com.entity.Car">
<property name="id" value="10"/>
<property name="name" value="本田"/>
</bean>
<bean id="person" class="com.entity.Person" autowire="byName">
<property name="id" value="11"/>
<property name="name" value="李四"/>
</bean>
</beans>
测试类
public class AutoWireBean {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-autowire.xml");
Person person = (Person) context.getBean("person");
System.out.println("person = " + person);
}
}
- byType属性:通过属性的数据类型自动装载
实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Car {
private Integer id;
private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private Integer id;
private String name;
private Car car;
}
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--这里的id属性名称可以不跟依赖实体类的对象的属性变量名,可以随便取名字-->
<bean id="cars" class="com.entity.Car">
<property name="id" value="10"/>
<property name="name" value="本田"/>
</bean>
<bean id="person" class="com.entity.Person" autowire="byType">
<property name="id" value="11"/>
<property name="name" value="李四"/>
</bean>
</beans>
测试类
public class AutoWireBean {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-autowire.xml");
Person person = (Person) context.getBean("person");
System.out.println("person = " + person);
}
}
其中byTye属性值需要注意的问题是:如果同时存在两个或者两个以上的符合的bean时,自动装载会报异常(不知道是取哪一个bean对象)