Spring深入浅出(二)IOC的单例 ,继承,依赖,JDBC,工厂模式以及自动装载
IOC的单例模式--Bean
Spring中的bean是根据scope来决定的。
scope有4种类型:
1.singleton:单例模型,表示通过Spring容器获取的该对象是唯一的。常用并且默认。
2.prototype:多例模型,表示通过Spring容器获取的对象都是不同的(类似于Java基础中new出来的对象地址是唯一的)。
3.reqeust:请求,表示在一次http请求内有效。
4.session:会话,表示在一个用户会话内有效。
1.创建一个对象
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2.在spring的l配置文件中将User的实例化。
<?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="user" class="com.test.entity.User">
<property name="id" value="1"></property>
<property name="name" value="User1"></property>
</bean> </beans>
3.测试类中通过Spring容器获取两个User实例化对象,并且通过==方法判断是否为同一个对象。
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
User u1 = (User) applicationContext.getBean("user");
User u2 = (User) applicationContext.getBean("user");
System.out.println(u1 == u2);
}
}
总结:看到结果打印true,表示user1和user2是同一个对象,所以scope默认值为singleton(单例模式),也就是用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"> <bean id="user" class="com.test.entity.User" scope="prototype">
<property name="id" value="2"></property>
<property name="name" value="User2"></property>
</bean> </beans>
Spring的继承
Spring的继承,与Java的继承不一样,子bean和父bean的方法一样,子bean可以继承父bean中的属性。
如果子bean继承父bean,同时子bean给属性赋值,那么会覆盖掉父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="user" class="com.test.entity.User">
<property name="id" value="1"></property>
<property name="name" value="张三1"></property>
</bean> <bean id="user2" class="com.test.entity.User" parent="user">
<!-- 覆盖掉user的name属性值 -->
<property name="name" value="张三2"></property>
</bean>
</beans>
Spring的依赖
与继承类似,依赖也是bean和bean之间的一种关联方式,配置依赖关系后,被依赖的bean一定先创建,再创建依赖的bean。
使用的关键字是depends-on="被依赖的bean的id"
<?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">
<!-- user依赖于car -->
<bean id="user" class="com.test.entity.User" depends-on="car">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean> <bean id="car" class="com.test.entity.Car">
<property name="id" value="1"></property>
<property name="brand" value="宝马"></property>
</bean> </beans>
上述代码执行顺序是:car-->user。先创建car,再创建user
Spring读取外部资源。
在开发中,类似于数据库等文件的配置会保存在一个properties文件中,便于维护,因此使用Spring需要来读取数据源对象。
1.先创建一个peoperties文件在路径下,具体位置根据项目需求来放置。
##key==value的形式
driverName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/shop
user = root
pwd = root
2.spring的配置文件中配置数据源,这里用到的是C3P0数据源。
<?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-4.0.xsd"> <!-- 导入外部的资源文件 -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder> <!-- 创建数据源 ,通过${}读取资源文件中的数据,${}中填写key,name中的值根据连接池的不同名字可能不同,尽量反编译代码去找一下对应的属性名-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="${user}"></property>
<property name="password" value="${pwd}"></property>
<property name="driverClass" value="${driverName}"></property>
<property name="jdbcUrl" value="${url}"></property>
</bean> </beans>
3.测试
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource ds = (DataSource) applicationContext.getBean("dataSource");
Connection conn = null;
try {
conn = ds.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(conn);
}
}
IOC通过工厂方法创建对象
Spring中的IOC是典型的工厂模式,那么如何使用工厂模式来创建bean?
IOC通过工厂模式创建bean有两种方式:
1.静态工厂方法
2.实例工厂方法
静态工厂实例化
1.先创建一个实体类
2.创建静态工厂类,静态工厂方法。
3.编写Spring的配置文件
4.编写测试类
//步骤1:创建一个实体类
public class Car {
private int num;
private String brand;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Car(int num, String brand) {
super();
this.num = num;
this.brand = brand;
}
public Car() {
super();
}
@Override
public String toString() {
return "Car [num=" + num + ", brand=" + brand + "]";
}
}
//步骤2:创建一个静态类
public class StaticCarFactory {
private static Map<Integer,Car> cars;
//静态代码块
static{
cars = new HashMap<Integer,Car>();
cars.put(1, new Car(1,"奥迪"));
cars.put(2, new Car(2,"宝马"));
}
//静态方法
public static Car getCar(int num){
return cars.get(id);
}
}
<?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对象 -->
<!-- factory-method:指向静态方法 getCar() -->
<bean id="car1" class="com.test.entity.StaticCarFactory" factory-method="getCar">
<!-- value为要生成的哪个对象的key -->
<constructor-arg value="1"></constructor-arg>
</bean> </beans>
//步骤4:测试类
public class Test {
public static void main(String[] args) throws SQLException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car) applicationContext.getBean("car1");
System.out.println(car);
}
}
实例工厂方法
1.创建实例工厂类,工厂方法 。
2.spring的配置文件中配置bean。
3.在测试类中直接获取car2对象。
//步骤1:创建实例工厂类
public class InstanceCarFactory {
private Map<Integer,Car> cars;
public InstanceCarFactory() {
cars = new HashMap<Integer,Car>();
cars.put(1, new Car(1,"奥迪"));
cars.put(2, new Car(2,"宝马"));
}
public Car getCar(int num){
return cars.get(num);
}
}
<?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="carFactory" class="com.test.entity.InstanceCarFactory"></bean> <!-- 通过实例工厂对象创建car对象 factory-bean:放置实例化的工厂对象bean的id,然后再设置factory-method:调用方法 -->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean> </beans>
测试类与静态工程的方式一样,并且结果也是生成key为1的car对象。
总结
两种方式的区别:
(1)使用静态工厂方法的方式创建car对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象即可调用。所以spring的配置文件只需要配置一个Car的bean,而不需要配置工厂bean。
(2)使用实例工厂方法创建car对象,必须先实例化工厂对象,因为调用的是非静态方法,必须通过对象调用,不能直接通过类来调用,所以spring的配置文件中需要先配置工厂bean,再配置Car bean。
IOC的自动装载
Spring框架提供了一种更加简便的方式:自动装载,不需要手动配置property,IOC容器会根据bean的配置自动选择bean完成依赖注入(DI)。
自动装载有两种方式:
byName:通过属性名自动装载。
byType:通过属性对应的数据类型自动装载。
//先创建一个实体类,并且生成setter/getter方法和toString方法
public class Person {
private int id;
private String name;
private Car car;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", car=" + car + "]";
} }
<?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"> <!--
创建person对象时,没有在property中配置car属性
所以IOC容器会自动进行装载
autowire="byName"表示通过匹配属性名的方式去装载对应的bean
Person实体类中有car属性,所以就将的bean注入到person中。
-->
<bean id="p1" class="com.test.entity.Person" autowire="byName">
<property name="id" value="1"></property>
<property name="name" value="ZhangSan"></property>
</bean> <bean id="car1" class="com.test.entity.StaticCarFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean> <!-- byType即通过属性的数据类型来配置。
关键字:autowire="byType"
-->
<bean id="p2" class="com.test.entity.Person" autowire="byType">
<property name="id" value="1"></property>
<property name="name" value="张三"></property>
</bean> <bean id="car2" class="com.test.entity.StaticCarFactory" factory-method="getCar">
<constructor-arg value="1"></constructor-arg>
</bean> </beans>
注意:
(1)使用了byType进行自动装载,如果spring的配置文件中配置了两个Car的bean,但是IOC容器不知道应该将哪一个bean装载到person对象中,因此可能会报错。所以在使用byType进行自动装载时,spring的配置文件中只能配置一个Car的bean才能使用byType。
(2)通过property标签手动进行属性的注入优先级更高,若自动注入和手动配置两种方式同时存在,则以property的配置为主。
所以在日常的代码编写过程中,尽量避免的使用byType去自动装配。
Spring深入浅出(二)IOC的单例 ,继承,依赖,JDBC,工厂模式以及自动装载的更多相关文章
- spring的controller默认是单例还是多例
转: spring的controller默认是单例还是多例 先看看spring的bean作用域有几种,分别有啥不同. spring bean作用域有以下5个: singleton:单例模式,当spri ...
- spring如何解决单例循环依赖问题?
更多文章点击--spring源码分析系列 1.spring循环依赖场景2.循环依赖解决方式: 三级缓存 1.spring循环引用场景 循环依赖的产生可能有很多种情况,例如: A的构造方法中依赖了B的实 ...
- 【开发者笔记】揣摩Spring-ioc初探,ioc是不是单例?
前言: 控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语.它包括依赖注入(Dependency Inject ...
- java-静态-单例-继承
概要图 一.静态 1.1 静态方法 创建对象就是为了产生实例,并进行数据的封装. 而调用功能时,确没有用到这些对象中封装的数据. 该对象的创建有意义吗?虽然可以编译并运行,但是在堆内存中空间较为浪费. ...
- 【Java面试宝典】说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理, aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的?
AOP与IOC的概念(即spring的核心) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度.而sprin ...
- Struts2 本是非单例的,与Spring集成就默认为单例
1.Struts2本身action类是多例,此设计的原因在于本身action担任了数据载体,如果做成单例,则会便多用户数据受到影响: 2.当Struts2 与 spring整合时,Struts2的Ac ...
- spring中如何向一个单例bean中注入非单例bean
看到这个题目相信很多小伙伴都是懵懵的,平时我们的做法大都是下面的操作 @Component public class People{ @Autowired private Man man; } 这里如 ...
- filter和spring 的interceptor都是单例的,都不是线程安全的
Filter 是在 Servlet 容器启动时就初始化的,因此可以认为是以单例对象存在的,如果一个请求线程对其中的成员变量修改的话,会影响到其他的请求线程,因此认为是多线程不安全的.
- 漫谈设计模式(二):单例(Singleton)模式
1.前言 实际业务中,大多业务类只需要一个对象就能完成所有工作,另外再创建其他对象就显得浪费内存空间了,例如web开发中的servlet,这时便要用到单例模式,就如其名一样,此模式使某个类只能生成唯一 ...
随机推荐
- Struts2中的异步提交(ajaxfileupload异步上传(图片)插件的使用)
server端採用struts2来处理文件上传. 所需环境: jquery.js ajaxfileupload.js struts2所依赖的jar包 及struts2-json-plugin-2.1. ...
- CCFlow的excel数据源导入Dtl明细表的操作方法以及模版demo
CCBPM支持通过excel向Dtl明细表(从表)导入数据. 以下,我们以cc的財务报销单demo流程解说详细的操作步骤和模版设计. 导入的操纵步骤: 1.流程发起后,在開始节点导入数据源,点击明细表 ...
- HDU 5375 Gray code(2015年多校联合 动态规划)
题目连接 : 传送门 题意: 给定一个长度为的二进制串和一个长度为n的序列a[],我们能够依据这个二进制串得到它的Gray code. Gray code中假设第i项为1的话那么我们就能够得到a[i] ...
- Android集成一个新产品时,lunch的product name和device name注意事项
Android系统lunch一个当前的Product大概流程包括下面几个部分: 1. lunch确定TARGET_PRODUCT.一般位于vendor/device/build/target/prod ...
- JAVA设计模式之【代理模式】
代理模式 通过代理对象间接访问 代购 客户端不想或者不能直接访问一个对象,可以通过一个称为代理的第三者来实现间接访问,该方案称为代理模式 角色 抽象主题角色Subject 声明真实主题类与代理类的公共 ...
- ES API 备忘
本文所列的所有API在ElasticSearch文档是有详尽的说明,但它的结构组织的不太好. 这篇文章把ElasticSearch API用表格的形式供大家参考. https://www.iteblo ...
- ubuntu下创建文件夹快捷方式
title: ubuntu下创建文件夹快捷方式 toc: false date: 2018-09-01 17:22:28 categories: methods tags: ubuntu 快捷方式 s ...
- sicily 1137 河床 (二分分治)
<计算机算法设计与分析>啃书中... 有点看不进书,就来刷个水题吧,刚开始看错题了还. 注意:是所有测量点相差均不大于di而不是相邻两点... //1137.河床 #include < ...
- 深入C#类的方法
构造函数 example1: static void Main(string [] args) { SE engineer=new SE(); engineer.Age=; enginner.Name ...
- jQuery学习(二)——使用JQ完成页面定时弹出广告
1.JQuery效果 2.步骤分析: 第一步:引入jQuery相关的文件 第二步:书写页面加载函数 第三步:在页面加载函数中,获取显示广告图片的元素. 第四步:设置定时操作(显示广告图片的函数) 第五 ...