Spring框架
Spring是分层的JavaSE/JavaEE应用一站式的轻量级开源框架,以IoC/DI和AOP为内核,提供了展现层SpringMVC和持久层SpringJDBC以及业务层事务管理等众多的企业级应用技术,并整合了大量的第三方框架和类库,逐步成为使用最多的JavaEE企业级应用开发框架
Hello Spring
用于总体的管理,主要简化对象的创建和依赖关系的管理,并依靠AOP可以抽离公共的业务逻辑处理
1、添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.6</version>
</dependency>
2、定义核心配置文件
<?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是受管bean的类全名-->
<bean id="now" class="java.util.Date"/>
</beans>
3、编程调用
public class A {
public static void main(String[] args) {
Resource resource=new ClassPathResource("beans.xml");
//Resource接口有2种具体实现
// 1、ClassPathResource在classpath路径下查找核心配置文件
//2、FileSystemResource在指定的路径下查找核心配置文件
//获取IoC容器的引用
BeanFactory facory=new XmlBeanFactory(resource);
//需要使用对象时根据受管bean的名称获取受管bean对象,由容器负责创建对象,并管理对象的生命周期
Object now=facory.getBean("now");
System.out.println(now);
}
}
OOP
设计模式六大原则:单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则
##单一职责原则SRP
一个类只负责一个功能领域中的相应职责。
单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。
##开闭原则OCP
一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在Java等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。
##里氏代换原则LSP
所有引用基类的地方必须能透明地使用其子类的对象。在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。
##依赖倒转原则DIP
抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。
依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。
##接口隔离原则ISP
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
##迪米特法则LoD
一个软件实体应当尽可能少地与其他实体发生相互作用。迪米特法则可降低系统的耦合度,使类与类之间保持松散的耦合关系。
##设计原则的选用
对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要刻板的遵守,而需要根据实际情况灵活运用。对遵守程度只要在一个合理的范围内,就算是良好的设计。
##JavaSE的设计模式
在1994年由四人合著出版了一本名为Design Patterns - Elements of Reusable Object-Oriented Software(设计模式 - 可复用的面向对象软件元素)的书,该书首次提到了软件开发中设计模式的概念。
GOF总结了JavaSE开发中常见的23种设计模式,可以分为3大类:创建型模式、结构型模式、行为型模式
JavaEE模式目前缺乏统一的说法。
JavaEE设计模式:关注表示层,如MVC模式(MVC Pattern) 数据访问对象模式DAO(Data Access Object Pattern) 前端控制器模式(Front Controller Pattern) … …
###单例模式
属于创建型模式,它提供了一种创建对象的最佳方式。
主要解决:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
#概述Spring框架
Spring是一个轻量级的控制反转IoC/DI依赖注入和面向切面AOP的开源容器框架,是一个开源的Java/Java EE全功能栈full-stack的应用程序框架,使用基本的 JavaBean【POJO】完成以前只可能由EJB完成的工作,取代了EJB臃肿和低效的开发模式。以Apache许可证形式发布
通常服务器端应用会采用三层体系架构,分别为表现层web、业务逻辑层service、持久层dao。Spring对每一层都提供了技术支持,它给予了 Java 程序员更高的自由度,对业界的常见框架提供了良好的整合解决方案
- 不重复发明轮子
- 锤子理论
##Spring优点
好的设计优于具体实现,代码应易于测试
1、方便解耦、简化开发(避免硬编码造成的过度耦合)
2、支持AOP编程,解耦通用功能
3、支持声明式事务,提供开发效率和质量
4、方便测试
5、方便集成各种优秀框架,降低API使用难度
##为什么要使用Spring?
- 简化企业级开发
- 封装了大部分的企业级服务,提供了更好的访问这些服务的方式
- 提供了IoC,AOP功能的容器,方便编程
- 遵循Spring框架的应用程序,一定是设计良好的,针对接口编程,这样就简化了企业级程序的设计。
##Spring体系结构
Spring是一种JavaEE开发中的一站式解决方案,所以其中包含的内容比较多,为了避免在应用中添加无用功能,所以Spring采用了非强制性的模块化结构,在具体应用中,可以根据应用所需要的功能进行选择添加。
Spring4+由6大模块20多个子项目构成,框架采用分层架构,根据不同的功能被划分成了多个模块,Spring的模块化是很强的,各个功能模块都是独立的,可以选择的使用
-
IoC将类之间的依赖关系从代码中脱离出来,用配置的方式进行依赖关系描述,由IoC容器负责依赖类之间的创建、管理和获取等工作
-
AOP进行横切逻辑编程,整合AspectJ这种AOP语言级的框架
-
Instrument允许在JVM启动时启用一个代理,通过该代理类在运行期修改类的字节码,改变一个类的功能
-
Test模块:支持Spring组件,使用JUnit或TestNG框架的测试
-
Data Access/Integration数据访问/集成
-
Web模块
Spring 5于2017年9月发布了通用版本GA,采用全新的编程范例以反应式原则为基础,要求将 Java 8作为最低的JDK版本,兼容 Java EE 8 技术,满足对 Servlet 4.0、Bean Validation 2.0 和全新的 JSON Binding API 的需求。
Spring总共有20个模块, 由1300多个不同的文件构成。而这些组件被分别整合在核心容器、AOP和设备支持 、数据访问与集成、Web、消息、测试6个模块中
###Spring框架的主要功能
基于Java Beans的配置管理,采用IoC的原理,特别是对依赖注入技术的使用。这些都用来减少各组件间对实施细则的相互依赖性。
- 一个核心的,全局适用的bean工厂
- 一个一般抽象化的层面来管理数据库间的数据处理
建立在框架内的,对Java数据处理API和单独的JDBC数据源的一般性策略。因此,在数据处理支持上对Java企业版本环境的依赖性得以消除和一些整合持久化的框架,如Hibernate,JDO,iBATIS和db4o的整合
web应用中的MVC框架,基于核心的Spring功能,支持多种产生视图的技术,包括JSP、FreeMarker、Velocity、Tiles、iText和POI
大量的AOP框架以提供诸如数据处理管理的服务。同IOC的功能一样,目的是提高系统的模块化程度
Spring框架4大原则
- 使用POJO进行轻量级和最小侵入式开发
- POJO简单的Java对象Plain Ordinary Java Object实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
- 通过控制反转IoC、依赖注入DI和基于接口编程实现松耦合
- 通过AOP和默认惯例进行声明式编程
- 使用AOP和模板编程减少模式化代码
##受管bean
Spring中那些组成应用的主体以及由Spring IoC容器所管理的对象被称之为bean。Bean就是由Spring容器初始化、装配以及被管理的对象
bean是Spring管理的基本单位,在Spring的应用中所有的组件都是bean,bean包括数据源、 Hibernate的SessionFactory及事务管理器等。 Spring里的bean是非常广义的概念,任何的Java对象,Java组件都可被当成bean处理。甚至这些组件并不是标准的JavaBean
###标签bean配置一个bean
在配置文件中使用id属性定义受管bean的名称,一般建议采用Java变量的命名规则,实际上使用123d或者12,3d都是可以的,需要注意Spring版本的区别。Id只能定义一个名称,如果需要定义多个可以使用name属性进行定义,这里使用id、name名称都可以获取受管bean。针对获取受管bean对象的名称而言,其它的名称都叫做别名
受管bean就是纳入到IoC/DI容器中,由容器负责创建和管理生命周期的javabean对象
<bean id=”受管bean的标识符,唯一,这里只能定义一个名称” class=”受管bean类的全名”
name=”别名,可以定义多个,使用逗号分隔”
scope=”范围,可以设置,默认singleton单例[Spring容器默认提供了单例模式的实现,不需要编码],
prototype原型,每次获取的都是新建的对象,另外还有和web相关的3个配置request、session、global session”/>
- Id命名建议采用Java变量的命名机制。注意Spring3-id命名规范比较严格,Spring3+命名中允许数字开头,允许使用包括空格在内的特殊符号,但是注意的是id只有一个名字,name允许使用特殊符号,是多个名称
- id命名中空格是名称的一部分,name可以使用空格或者逗号分隔多个名称
受管bean的要求:一般来说任何java类都可以作为受管bean
- class指向全类名,spring就是根据全类名,通过反射生成一个实例对象,id为这个实例对象的引用,所以必须在这个类中添加默认的构造方法,并且属性要有setter方法
scope设置受管bean范围
- singleton单例,是默认属性:Spring将Bean放入Spring IoC容器的缓存池中,并将Bean引用返回给调用者,spring IoC容器负责对这些Bean进行后续的生命管理。BeanFactory只管理一个共享的实例。所有对这个特定bean的实例请求,都导致返回这个唯一bean实例的引用。即每次拿到的对象都是引用的同一个地址的对象。当一个bean被标识为singleton时候,spring的IoC容器中只会存在一个该bean
- prototype原型:不管是BeanFactory或者ApplicationContext都是延迟加载使用的。每次对这个bean的实例请求都会导致一个新的实例的创建。当用户需要不受其他用户对象影响的对象或有类似的需求时,这是一个较理想的解决办法。即每次拿到的对象都是引用的不同地址的对象。相当于一个new的操作。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责
- 以下3种scope都使用的较少,有request\session\global session,类似于JavaEE里面的request和session。在使用SpringMVC是可能会用到
- request表示针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
- session表示一个用户【客户】对应一个新的bean
- global session作用域类似于标准的HTTPSession作用域,不过仅仅在基于portlet的web应用中才有意义
注意:对于struts2中的Action来说需要指明scope=prototype,因为struts2的Action要求是多实例、单线程的
总结
Spring是一个轻量级的控制反转IoC/DI依赖注入和面向切面AOP的开源容器框架,是一个开源的Java/Java EE全功能栈full-stack的应用程序框架,以Apache许可证形式发布
Spring是一个轻量级的DI/IoC和AOP容器框架。存在的目的是用于构建轻量级的JavaEE应用。
Spring以一种非侵入式的方式来管理你的代码,Spring提倡”最少侵入”,这也就意味着你可以适当的时候安装或卸载Spring
- 目的:解决企业应用开发的复杂性
- 功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
- 范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
#IoC和DI容器
问题
IUserDao接口 — 多个不同实现MySQLUserDao OracleUserDao …
###工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
主要解决:主要解决接口选择的问题。
优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
1、创建接口
public interface IUserDao {
public void save();
}
2、若干实现
public class MySqlUserDao implements IUserDao{
@Override
public void save() {
System.out.println("使用MySQL数据库存储数据....");
}
}
3、创建一个工厂,生成基于给定信息的实现类的对象
public class DaoFactory {
public IUserDao getUserDao(String str){
if(str==null)
return new UserDaoImpl();
if("mysql".equals(str))
return new MySqlUserDao();
else
return new UserDaoImpl();
}
}
4、通过工厂对象获取接口的实现类对象
DaoFactory fac=new DaoFactory();
IUserDao userDao=fac.getUserDao(null);
userDao.save();
userDao=fac.getUserDao("mysql");
userDao.save();
5、假设又有DB2的实现
public class Db2UserDao implements IUserDao{
@Override
public void save() {
System.out.println("使用DB2数据库存储数据......");
}
}
修改DaoFactory
public class Db2DaoFactory extends DaoFactory{
@Override
public IUserDao getUserDao(String str) {
if("db2".equals(str))
return new Db2UserDao();
return super.getUserDao(str);
}
}
问题:产品可扩展,但是产品的系列不可扩展
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
产品1对应的接口:
public interface Shape {
void draw();
}
每个产品接口有多种实现
public class Circle implements Shape {
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
产品2对应的接口:
public interface Color {
void fill();
}
每个产品接口有多种实现
public class Red implements Color {
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}
因为一个接口多种实现,所以需要顶一个一个工厂,但要2个工厂。为Color和Shape对象创建抽象类来获取工厂。
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
针对具体产品的工厂定义
public class ShapeFactory extends AbstractFactory {
public Shape getShape(String shapeType){
if(shapeType == null) return null;
if(shapeType.equalsIgnoreCase("CIRCLE")) return new Circle();
return null;
}
public Color getColor(String color) {
return null;
}
}
一个工厂只能生产一种商品
public class ColorFactory extends AbstractFactory {
public Shape getShape(String shapeType){
return null;
}
public Color getColor(String color) {
if(color == null) return null;
if(color.equalsIgnoreCase("RED")) return new Red();
return null;
}
}
具体调用
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
工厂扩展
可以将具体实体类的名称剥离出来,定义在properties文件中
userdao=com.yan.dao.MySqlUserDao
定义工厂
public class DaoFactory {
public Object getBean(String name)throws Exception{
//使用类加载器获取abc.properties文件的输入流
InputStream is=DaoFactory.class.getResourceAsStream("abc.properties");//注意properties文件的存放位置必须和当前类一致
Properties ps=new Properties();
ps.load(is);
if(name!=null){
String className=ps.getProperty(name); //获取name对应的类的全名
//使用反射机制调用具体类中的无参构造器创建对应的对象
return Class.forName(className).newInstance();
}
return null;
}
}
只要修改properties文件则可以生产任何产品:产品可扩展、产品系列可扩展
问题:
因为properties文件语法不严格,所以引入xml配置
###xml
xml可扩展标记语言,允许自定义标签
在具体的应用中需要对xml进行语法说明,以实现xml文件的解析
####XML的语法说明
xml文件有3种类型:无效的、良构的和有效的
语法说明: dtd文档类型定义
xsd模式定义
解析模型: DOM解析 文档对象模型 在内存中构建DOM树
SAX简单xml编程接口 基于流的事件处理
编程工具:XML的解析方式分为四种:1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。
其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,
只适用于java平台
使用JAXP
SAX解析方式是根据事件驱动一行一行进行加载解析的,所以不会出现内存溢出的问题,而且方便查询,
但是它有个缺点:不能进行增删改操作
<?xml version="1.0" encoding="UTF-8" ?>
<books>
<book id="1">
<title>计算机讲义</title>
<price>12.34</price>
<author>猴子</author>
</book>
<book id="2">
<title>爱情宝典</title>
<price>999</price>
<author>黄毛</author>
</book>
</books>
对这个文件进行解析,使用SAX模型
public class Test1 {
public static void main(String[] args) throws Exception {
//获取SAX解析器工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//通过SAX解析器工厂获取SAX解析器
File f=new File("books.xml");
SAXParser parser=factory.newSAXParser(); //自动选择系统默认的解析器
parser.parse(f,new DefaultHandler(){
@Override
public void startDocument() throws SAXException {
System.out.println("开始解析文档");
}
@Override
public void startElement(String uri, String localName,String qName, Attributes attributes) throws SAXException {
System.out.println("标签名称为:"+qName);
System.out.println("标签的属性为:"+ attributes);
System.out.println("某个标签开始");
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
System.out.println("处理标签体");
//具体的标签体内容位于ch数组中,从start位置开始,共length个长
String ss=new String(ch,start,length);
System.out.println(ss);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
System.out.println("标签结束"+qName);
}
@Override
public void endDocument() throws SAXException {
System.out.println("文件解析完毕");
}
});
}
}
读取并解析数据后进行存储
构建一个实体类
@Data
public class Book{
private Long id;
private String title;
private Double price;
private String author;
}
修改解析处理逻辑
public class Test1 {
public static void main(String[] args) throws Exception {
final List<Book> bookList=new ArrayList<>();
//获取SAX解析器工厂
SAXParserFactory factory=SAXParserFactory.newInstance();
//通过SAX解析器工厂获取SAX解析器
File f=new File("books.xml");
SAXParser parser=factory.newSAXParser(); //自动选择系统默认的解析器
parser.parse(f,new DefaultHandler(){
private Book book;
private int flag=0;
@Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
if("book".equals(qName)){
String ss=attributes.getValue("id");
book=new Book();
Long bookId=null;
try{
bookId=Long.parseLong(ss.trim());
book.setId(bookId);
}catch (Exception e){
throw new SAXException(e);
}
}else if("title".equals(qName))
flag=1;
else if("price".equals(qName))
flag=2;
else if("author".equals(qName))
flag=3;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
String ss=new String(ch,start,length);
if(ss!=null && ss.trim().length()>0){
if(flag==1)
book.setTitle(ss.trim());
else if(flag==2){
Double dd=Double.parseDouble(ss.trim());
book.setPrice(dd);
}else if(flag==3)
book.setAuthor(ss.trim());
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
flag=0;
if("book".equals(qName))
bookList.add(book);
}
});
bookList.forEach(System.out::println);
}
}
Beanfactory的配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans>
<bean id="userDao" class="com.yan.dao.MySqlUserDao"/>
</beans>
BeanFactory功能:
- 使用SAX解析器解析读取配置文件
- 按照class属性值中所指定的具体类全名创建对象
- 按照id属性值将创建的对象存储在Map中
- getBean(String id):Object按照名称查找由容器负责创建具体的对象
public class BeanFactory {
//按照目前的写法,没有必要使用ConcurrentHashMap
private static Map<String,Object> map=new ConcurrentHashMap<>();
static{
try{
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
File f=new File("src/main/resources/beans.xml");
parser.parse(f,new DefaultHandler(){
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if("bean".equals(qName)){
try {
String id = attributes.getValue("id");
String className = attributes.getValue("class");
Object obj = Class.forName(className.trim()).newInstance();
map.put(id.trim(), obj);
} catch (Exception e){
throw new SAXException(e);
}
}
}
});
}catch (Exception e){
e.printStackTrace();
}
}
public static Object getBean(String name){
if(map.containsKey(name))
return map.get(name);
return null;
}
}
Spring全方位解决方案
- ssm=SpringMVC+Spring+MyBatis [一般开发中常用,尤其是互联网应用开发类型的公司,一般中小型快速开发中应用]
- ssh[2]=Struts2+Spring+Hibernate [使用较少,一般在大型软件公司中长期使用,考试居多]
概述IoC
IoC控制反转Inversion of control不是什么技术,而是一种设计思想。在Java开发中,IoC意味着将设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。IoC是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则
样例:连接池
成品连接池: DBCP HikariCP Druid C3P0
添加依赖
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.8.0</version>
</dependency>
添加配置beans.xml
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="initialSize" value="10"/>
</bean>
编码调用
Resource r=new ClassPathResource("beans.xml");
BeanFactory factory=new XmlBeanFactory(r);
DataSource ds=(DataSource) factory.getBean("dataSource");
Connection conn=ds.getConnection();
System.out.println(conn);
IoC用途
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导如何设计出松耦合、更优良的程序。传统应用程序都是在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试; 有了IoC容器后, 把创建对象和查找依赖对象的控制权交给了容器, 由容器进行注入组合对象, 所以对象与对象之间是松散耦合, 这样也方便测试, 利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活.
其实,IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了"主从换位"的变化,应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了
基本概念
- IoC容器
简单的理解就是,实现IoC思想,并提供对象创建、对象装配以及对象生命周期管理的软件就是IoC容器 - IoC理解
1、应用程序无需主动new对象;而是描述对象应该如何被创建即可,IoC容器帮你创建,即被动实例化;
2、应用程序不需要主动装配对象之间的依赖关系,而是描述需要哪个服务,IoC容器会帮你装配,被动接受装配;
3、主动变被动,以前创建对象、装配对象的依赖关系都是由应用程序主动完成,现在变成被动了由IoC容器来完成
4、应用程序不知道依赖的具体实现,只知道需要提供某类服务的对象,达到并松散耦合;
5、是一种让服务消费者不直接依赖于服务提供者的组件设计方式,是一种减少类与类之间依赖的设计原则
- 使用Ioc/DI容器开发需要改变思路
1、应用程序不主动创建对象,但是要描述创建它们的方法
2、在应用程序代码中不直接进行服务的装配,但是要描述哪一个组件需要哪一项服务,由容器负责将这些装配在一起
也就是说:所有的组件都是被动的,组件初始化和装配都由容器负责,应用程序只是获取相应的组件后,实现应用的功能即可