一.遇到的问题
1:代码高耦合
public class EmployeeServiceImpl {
//依赖DAO
private IEmployeeDAO employeeDAO = new EmployeeDAOImpl();
}
问题:若把IEmployeeDAO的实现改成:EmployeeMapper.
----->简单工厂设计模式
----->把创建对象的职责交给工厂来管理.
到底工厂创建哪一个类的对象呢?我们是配置在配置文件中的(properties/xml).
2:业务代码中处理事务的繁琐问题
对于事务操作,代码冗余,必须在所有需要控制事务的地方,手动用代码完成几乎完全相同的事务控制逻辑,开发效率低下,并且难以方便的处理事务嵌套需求。
如何降低业务逻辑部分之间耦合度,提高程序的可重用性,同时提高开发的效率!—> AOP
主要分散在方法前后,在真正的业务操作前后的代码,我们可以使用面向切面编程来解决.
EmployeeService{
public void save(...){
//开启事务
dao.save(...);
//提交事务
}
public void update(...){
//开启事务
dao.update(...);
//提交事务
}
}
3:使用表现层和持久层框架的繁琐步骤
二.Spring介绍
什么是spring:
1、Spring是一个轻量级的DI/IoC和AOP容器的开源框架,来源于Rod Johnson 在其著作《Expert one on one J2EE design and development》中阐述的部分理念和原型衍生而来。
2、Spring提倡以”最少侵入”的方式来管理应用中的代码,这意味着我们可以随时安装或卸载Spring。
使用范围:任何Java应用
Spring根本使命:简化Java开发
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,致力于构建轻量级的JavaEE应用
Spring中常见术语:
1、应用程序:是能完成我们所需要功能的成品,比如购物网站、OA系统。
2、框架:是能完成一定功能的半成品,比如我们可以使用框架进行购物网站开发;框架做一部分功能,我们自己做一部分功能,这样应用程序就创建出来了。而且框架规定了你在开发应用程序时的整体架构,提供了一些基础功能,还规定了类和对象的如何创建、如何协作等,从而简化我们开发,让我们专注于业务逻辑开发。
3、非侵入式设计:从框架角度可以这样理解,无需继承框架提供的类,这种设计就可以看作是非侵入式设计,如果继承了这些框架类,就是侵入设计,如果以后想更换框架之前写过的代码几乎无法重用,如果非侵入式设计则之前写过的代码仍然可以继续使用。
4、轻量级及重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。
5、POJO:POJO(Plain Old Java Objects)简单的Java对象,它可以包含业务逻辑或持久化逻辑,但不担当任何特殊角色且不继承或不实现任何其它Java框架的类或接口。
6、容器(Container):在日常生活中容器就是一种盛放东西的器具,从程序设计角度看就是装对象的的对象,因为存在放入、拿出等操作,所以容器还要管理对象的生命周期。
Spring的优势:
1.低侵入/低耦合(降低组件之间的耦合度,实现软件各层之间的解耦。)
2.声明式事务管理
3.方便集成其他框架
4.降低JavaEE开发难度
5.Spring框架中包括JavaEE三层的每一层的解决方案 (一站式)
Spring能帮我们做什么:
①.Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。
②.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
③.Spring能非常简单的帮我们管理数据库事务。
④.Spring还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板来方便数据库访问。
⑤.Spring还提供与第三方Web(如Struts1、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
⑥.Spring能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。
Spring框架版本:
Spring2.5:
拥抱驱动编程。
支持SimpleJdbcTemplate的命名参数操作。
Spring3.x:
不再支持JDK1.4;
全面支持泛型。
支持SpEL.
支持WebService的OXM。
Spring4.x:
支持Java8,支持JavaEE6规范。
泛型限定式依赖注入。
对Hibernate4的集成和事务提供更好的管理方案。
Spring框架包分析:
现在都提倡使用Maven去下载Spring的jar:
下载地址:http://repo.spring.io/libs-release-local/org/springframework/spring/
spring-framework-4.x.RELEASE:Spring核心组件。
docs: Spring开发、帮助文档。
libs: Spring核心组件的。jar包、源代码、文档。
schema: Spring配置文件的schema约束文件。
spring-framework-3.x.RELEASE-dependencies:Spring依赖的第三方组件。
包含了各大开源组织提供的依赖jar。比如apache common下的:dbcp.jar pool.jar logging.jar
三.IoC和DI简单介绍
IoC:Inverse of Control(控制反转):
读作“控制反转”,更好理解,不是什么技术,而是一种设计思想,好比于MVC。就是将原本在程序中手动创建对象的控制权,交由Spring框架来管理。
正控:若调用者需要使用某个对象,其自身就得负责该对象的创建。
反控:调用者只管负责从Spring容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了Spring框架。
在这里完美地体现了好莱坞法则(Don’t call me ,I’ll call you)。
DI:Dependency Injection(依赖注入):
从字面上分析:
IoC:指将对象的创建权,反转给了Spring容器;
DI :指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。
IoC和DI其实是同一个概念的不同角度描述,DI相对IoC而言,明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Container:
容器,在生活中容器就是一种盛放东西的器皿,从程序设计角度看作是装对象的对象,因为存在对对象的存入、取出等操作,所以容器还要管理对象的生命周期。
四.案例 helloworld
//准备jar包(核心包)
spring-beans-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
//报错再添加:
commons.logging-1.2.jar
创建applicationContext.xml
通过import分模块引入各个模块的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">
<!--引入各个模块的bean.xml-->
<import resource="classpath:gzcPro/spring/_01helloSpring/hello.xml"></import>
<import resource="classpath:gzcPro/spring/_02instance/content/App_context.xml"></import>
</beans>
创建hello.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">
<!-- Ioc: 控制反转 将class交给spring容器管理-->
<bean id="helloWorld" class="gzcPro.spring._01helloSpring.HelloWorld">
<!--DI:依赖注入-->
<property name="name" value="桂志超"></property>
</bean>
</beans>
创建App_context.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">
<!-- Ioc: 控制反转 将class交给spring容器管理
lazy-init是否在打开spring容器时就加载 false为不延时加载 true为延时加载
一般默认为false启动初始化所有的bean 不写-->
<bean id="someBean" class="gzcPro.spring._02instance.SomeBean" lazy-init="false">
</bean>
</beans>
创建HelloWorld.java
package gzcPro.spring._01helloSpring;
import lombok.*;
/**
* Created by Administrator on 2019/8/1.
*/
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Setter
@Getter
public class HelloWorld {
private String name;
public void sayHello(){
System.out.println("hello:"+ name);
}
}
创建SomeBean.java
package gzcPro.spring._02instance;
import lombok.*;
/**
* Created by Administrator on 2019/8/1.
*/
@ToString
@Setter
@Getter
public class SomeBean {
public SomeBean(){
System.out.println("bean被创建了");
}
}
创建测试代码APP.java
@Test
public void Ioc(){
//加载spring容器配置文件
Resource resource = new ClassPathResource("applicationContext.xml");
//启动spring容器
BeanFactory factory=new XmlBeanFactory(resource);
//way-01 getBean 需要强转(不推荐) 容器中可能有多个相同id
//HelloWorld helloWorld=(HelloWorld) factory.getBean("helloWorld");
//way-02 getBean 容器中可能有多个相同class(不推荐)
//HelloWorld helloWorld= factory.getBean(HelloWorld.class);
//way-03 getBean (推荐)
HelloWorld helloWorld= factory.getBean("helloWorld",HelloWorld.class);
System.out.println(helloWorld);
}
bean被创建了
HelloWorld(name=桂志超)
applicationContext.xml 中包含App_context.xml
如下模拟所说,会获取空的构造函数,所以下面代码执行了
public SomeBean(){ //空的构造函数
System.out.println("bean被创建了");
}
Spring管理bean的原理:
什么是BeanFactory:
Spring最基本的接口,表示Spring容器——生产bean对象的工厂,负责配置,创建和管理bean。
备注:bean是Spring管理的单位,在Spring中一切都是bean.
深入Spring管理bean的原理:
1、通过Resource对象加载配置文件;
2、解析配置文件,得到指定名称的bean;
3、解析bean元素,id作为bean的名字,class用于反射得到bean的实例:
模拟spring容器实现:
//模拟spring容器实现
@Test
public void test() throws Exception {
//模拟xml数据
String className = "gzcPro.spring._01helloSpring.HelloWorld";
String propertyName = "name";
String propertyValue = "桂志超";
//模拟spring操作:IOC 内省
Class<?> aClass = Class.forName(className);
//获取空参构造器
Constructor<?> declaredConstructors = aClass.getDeclaredConstructor();
//允许访问
declaredConstructors.setAccessible(true);
HelloWorld helloWorld = (HelloWorld) declaredConstructors.newInstance();
//通过内省 赋值DI
BeanInfo beanInfo = Introspector.getBeanInfo(aClass, Object.class);
//获取描述器
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd:propertyDescriptors) {
if (propertyName.equals(pd.getName())){
pd.getWriteMethod().invoke(helloWorld,propertyValue);
}
}
System.out.println(helloWorld);
helloWorld.sayHello();
}
HelloWorld(name=桂志超)
hello:桂志超
说到底,Ioc就是在配置文件中 添加bean对象, DI就是在对象在添加属性值
单元测试说明
junit4.12 hamcrest-core-1.3.jar
junit-4.12.jar
spring-test-4.2.4.RELEASE.jar. //单元测试
spring-context-4.2.4.RELEASE.jar. //
spring-aop-4.2.4.RELEASE.jar. //
spring-expression-4.2.4.RELEASE.jar. //
将 spring容器拿出来,不用每次都创建spring容器
/**
* Created by gzc on 2019/8/1.
*/
@RunWith(SpringJUnit4ClassRunner.class)//引入spring单元测试
@ContextConfiguration("classpath:applicationContext.xml")//引入配置文件
public class App {
//自动从spring容器中获取这个bean
@Autowired
private HelloWorld helloWorld;
@Test
public void test1() throws Exception {
System.out.println(helloWorld);
}
}
@Autowired 自动从spring容器中获取这个bean(bean是存在的)
@RunWith(SpringJUnit4ClassRunner.class)//引入spring单元测试
@ContextConfiguration(“classpath:applicationContext.xml”)//引入配置文件
@Autowired
private HelloWorld helloWorld;
取代了----------->
//加载spring容器配置文件
Resource resource = new ClassPathResource(“applicationContext.xml”);
//启动spring容器
BeanFactory factory=new XmlBeanFactory(resource);
HelloWorld helloWorld= factory.getBean(“helloWorld”,HelloWorld.class);
IoC容器:BeanFactory和ApplicationContext对象
BeanFactory:是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
在应用中,一般不使用BeanFactory,而推荐使用ApplicationContext(应用上下文),原因如下。
BeanFactory和ApplicationContext的区别:
1、ApplicationContext继承了BeanFactory,拥有了基本的IoC功能;
2、除此之外,ApplicationContext还提供了以下的功能:
①、支持国际化;
②、支持消息机制;
③、支持统一的资源加载;
④、支持AOP功能;
package gzcPro.spring._02instance.content;
import ...
/**
* Created by gzc on 2019/8/1.
*/
//@RunWith(SpringJUnit4ClassRunner.class)//引入单元测试
//@ContextConfiguration("classpath:applicationContext.xml")//引入配置文件
public class App {
//自动从spring容器中获取这个bean
// @Autowired
// private ApplicationContext context;
@Test
public void testAppCtx(){
ApplicationContext context = new ClassPathXmlApplicationContext("gzcPro/spring/_02instance/content/App_context.xml");
SomeBean someBean1=context.getBean("someBean",SomeBean.class);
SomeBean someBean2=context.getBean("someBean",SomeBean.class);
System.out.println(someBean1==someBean2);
}
}
ApplicationContext context = new ClassPathXmlApplicationContext(“gzcPro/spring/_02instance/content/App_context.xml”);
开启App_context.xml spring容器中的所有bean
---------------------------------------------------》换成
@ContextConfiguration(“App_context.xml”)//引入配置文件
或者(@ContextConfiguration(“classpath:applicationContext.xml”)//引入配置文件)
@Autowired
private ApplicationContext context;
/**
* Created by gzc on 2019/8/1.
*/
@RunWith(SpringJUnit4ClassRunner.class)//引入单元测试
//@ContextConfiguration("classpath:applicationContext.xml")//引入配置文件
@ContextConfiguration("App_context.xml")//引入配置文件
public class App {
//自动从spring容器中获取这个bean
@Autowired
private ApplicationContext context;
@Test
public void testAppCtx(){
SomeBean someBean1=context.getBean("someBean",SomeBean.class);
SomeBean someBean2=context.getBean("someBean",SomeBean.class);
System.out.println(someBean1==someBean2);
}
}