1.EJB存在的概念
2. 什么是Spring
Spring是一个轻量级的JavaEE解决方案,整合众多优秀的设计模式
- 轻量级
1、对运行环境是没有额外要求的、
开源:tomcat resion jetty
收费:weblogic websphere
2、代码移植性框架
不需要实现额外接口
- JavaEE的解决方案
-整合设计模式
1、工厂模式
2、代理模式
3、模板模式
4、策略模式
。。。
3.设计模式
1).广义概念
面向对象设计中,解决特定问题的经典代码
2).狭义概念
GOF四人帮定义的23种设计模式:工厂、适配器、装饰器、门面、代理、模板。。。。
想了解更多设计模式可以去看小编的另一篇文章 “23种设计模式你知道有哪些吗?”
4.工厂模式
4.1 什么是工厂模式
1.概念:通过工厂类,创建对象
通常我们都是通过下面的方式来创建对象
User user = new User();
UserDAO userDAO = new UserDAOImpl;
2.好处:解耦合
耦合:指的是代码间的强关联关系,一方面的改变会影响到另一方面
问题:不利于代码维护
简单:把接口的实现类,硬编码在程序中
4.2 简单工厂的设计
package com.myspring.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class BeanFactory {
//通过使用配置文件的方式解耦合工厂方法
private static Properties properties = new Properties();
static {
try {
//第一步 获取iO输入流 读取配置文件
InputStream springContent = BeanFactory.class.getResourceAsStream("/applicationSpringContent.properties");
//第二部 文件内容 封装到 properties集合中 key=ccom.myspring.test.UserServiceImpl
properties.load(springContent);
} catch (IOException e) {
e.printStackTrace();
}
}
//通过工厂类创建的UserService工厂方法
public static UserService getUserService() {
UserService userService = null;
try {
Class clazz = Class.forName(properties.getProperty("UserService"));
userService = (UserService) clazz.newInstance();
} catch (ClassNotFoundException e) {
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userService;
}
//通过工厂类创建的UserDAO工厂方法
public static UserDAO getUserDAO() {
UserDAO userDAO = null;
try {
Class clazz = Class.forName(properties.getProperty("UserDAO"));
userDAO = (UserDAO) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userDAO;
}
}
//我们后面就可以通过这样的方式来获取对象
UserService userService = BeanFactory.getUserService();
UserDAO userDAO=BeanFactory.getUserDAO();
//配置文件applicationSpringContent.properties
UserService = com.myspring.test.UserServiceImpl
UserDAO = com.myspring.test.UserDAOImpl
4.3 通用工厂设计
- 问题
简单工厂会出现大量冗余
- 解决 通用工厂的代码
//通用工厂创建对象(key代表配置文件种的key)
public static Object getBean(String key){
Object obj=null;
try {
Class clazz=Class.forName(key);
obj=clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
4.4 通用工厂的使用方式
1.定义类型(类)
2.通过配置文件的配置告知工厂(applicationSpringContent.properties)
key=value
3.通过工厂获取类的对象
Object obj = BeanFactory.getBean(key);
5.总结
二、第一个Spring程序spring本质:工厂 ApplicationContent 配置文件(applicationContent.xml)
1.软件版本
1.JDK1.8+
2.Maven3.5+
3.IDEA2018+
4.Springframework 5.1.4
Spring官方网站 www.spring.io
2.环境搭建
- Spring的jar包
#设置 pom 依赖org.springframework spring-context 5.1.4.RELEASE
- Spring的配置文件
1.配置文件的放置位置:任意位置 没有硬性要求
2.配置文件的命名 :没有硬性要求 建议: applicationContext.xml
思考:日后应用Spring框架时,需要进行配置文件路径的设置。
下面是我们新建配置文件的方式,聪明的idea给我们提供了快捷的方式来创建配置文件
3.Spring的核心API
- ApplicationContext
作用: Spring提供的ApplicationContext这个工厂,用于对象的创建
好处:解耦合
- ApplicationContext接口类型
接口:屏蔽实现的差异
非web环境:ClassPathXmlApplicationContext (用于main函数、junit单元测试)
web环境:XmlWebApplicationContext
- 重量级资源
AppilicationContext工厂的对象占用大量内存
不会频繁的创建对象:一个应用只会创建一个工厂对象
ApplicationContext:一定是线程安全的(多线程并发访问)
4.程序开发
- 创建类型
这里的类型指的是我们需要的类=====我们这里随便创建了一个person类
2.配置文件配置 applicationContext.xml
3.通过工厂类获得对象
ApplicatonContext
|-ClassPathXmlApplicationContext
//Spring第一个程序开发
@Test
public void test2() {
//1.获取Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
//2.通过工厂 获取对象
Person person = (Person) applicationContext.getBean("person");
//打印一下对象
System.out.println(person);
}
// 控制台输出:com.myspring.classdemo.Person@6b0c2d26
5.细节分析
- 名词解释
Spring工厂创建对象,叫做bean或者组件(component)
-Spring工厂相关的方法
//Spring工厂方法细节分析
@Test
public void test3() {
//获取Spring工厂
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/applicationContext.xml");
//通过这种重载的方式获取对象 就不需要强制类型转换了
Person person = applicationContext.getBean("person", Person.class);
System.out.println("person="+person);
//通过这种方式获取对象 当前Spring配置文件种只能有一个
- 配置文件中需要注意的细节
1.只配置class属性
问题:上述这种配置有没有id值?
答:有 “com.myspring.classdemo.Person#0”Spring工厂通过算法帮我们默认生成了一个id值
应用场景:如果这个bean只需要使用一次,那么就可以省略id值
注意事项:如果这个bean会使用多次,或者被其他bean引用则需要设置id值
2.name属性
作用:用于在Spring配置文件中,为bean对象定义别名(小名)
————————————————————————————————————
相同:
1) applicationContext.getBean(“id/name”)—>object 通过这种方式id或者name都可以获取对象
2) 等效
—————————————————————————————————————
区别:
1)别名可以定义多个,但是id属性只能有一个值
2)历史遗留问题>>>Xml的id属性的值,命名要求:必须以字母开头。字母、数字、下划线、连字符、不能以特殊字符开头
name属性的值,命名没有要求 /person BUT(但是)-> name属性会应用在特殊命名的场景下
XML的命名方式到现在ID属性的限制以及不存在了
3)代码
//判断Spring配置文件中是否存在指定id值的bean
//当配置文件显式定义了id时,只判断id 不判断name ,没有显式定义id时,也可以判断name
boolean a = applicationContext.containsBeanDefinition("a");
System.out.println(a);
//判断Spring配置文件中是否存在指定id值的bean
//id 和 name 都可以判断
boolean person1 = applicationContext.containsBean("person");
System.out.println(person1);
6.Spring工厂的底层实现原理(简易版)
Spring工厂是可以调用对象私有的构造方法创建对象
7.思考
问题:未来在开发过程中,是不是所有的对象,都会交给Spring工厂来创建呢?
回答:理论上 是的,但是有特例:实体对象(entity)是不会交给Spring创建,它是由持久层框架进行创建。
三、Spring5.x与日志框架的整合
Spring与日志框架进行整合,日志框架就可以在控制台中输出Spring框架运行过程中的一些重要信息。
好处:便于了解Spring框架的运行过程,利于程序的调试
- Spring如何整合日志框架
默认
Spring1.2.3早期都是于commons-logging.jar整合
Spring5.x 默认整合的日志框架是 logback/log4j2
我们这里不使用默认的logbak与log4j2,使用log4集成。
Spring5.x 整合log4j
1)引入log4j-jar包
2引入log4j。properties配置文件
pom.xml文件
org.slf4j
slf4j-log4j12
1.7.25
log4j
log4j
1.2.17
log4j.properties文件
#resources文件夹根目录下
###配置根
log4j.rootLogger = debug,console
###日志输出到控制台显示
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
四、注入(Injection)
1、什么是注入
通过Spring工厂及配置文件,为所创建对象的成员变量赋值
1.1 为什么需要注入
通过编码的方式为成员变量进行赋值,存在耦合
1.2 如何进行注入【开发步骤】
- 类的成员变量提供set get方法
- 配置Spring的配置文件
111
yuxw
1.3注入好处
解耦合
2.Spring注入的原理分析(简易版)
Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方式我们也称之为set注入
五、set注入详解
针对于不同类型的成员变量,在 《property》 标签,需要嵌套其他标签
《property》
XXXX
《/property》
1. JDK内置类型
1.1 String + 8种基本类型
xxxx
1.2数组
//成员变量:private String[] emils;
This A
This B
This C
This D
1.3set集合
//成员变量:private Set tels;
//基本类型+String
123456
23456
3456
//或者自定义类型的值 指:泛型中的对象类型 如果没有泛型则是Object类型
1.4List集合
//成员变量:private List addresses;
1.5Map集合
注意:map ---entry---key有特定的标签
值:根据对应类型选择对应的标签
//成员变量: private Map qqs;
1.6Properties集合
//成员变量:private Properties properties;
This value1
This value2
1.7复杂的JDK类型(Date)
需要程序员自定义类型转换器,处理。
在赋值集合时我们要去考虑泛型的问题!!!
因为我们集合中可以存储自定义类的数据类型所以我们要特别的关注一下。
2. 用户自定义类型
2.1 第一种方式
- 为成员变量提供get set 方法
- 配置文件中进行注入(赋值)
2.2 第二种方式
- 第一种赋值方式存在的问题
1.配置文件代码冗余
2.被注入的对象(UserDAO),多次创建,浪费(JVM)内存资源
- 为成员变量提供set/get方法
- 配置文件中进行配置
#Spring4.x 废除了 基本等效于
3.Set注入的简化写法
3.1基于属性简化
JDK类型注入
xxx
简化
注意!!! value属性只要能简化 8种基本类型+String 注入标签
-------------------------------------------
用户自定义类型
3.2基于p命名空间简化
bugz
1233333
简化
注意!!! value属性只要能简化 8种基本类型+String 注入标签
-------------------------------------------
用户自定义类型
简化
六、构造注入
注入:通过Spring的配置文件,为成员变量赋值
Set注入:Spring 调用Set方法 通过配置文件为成员变量赋值
构造注入:Spring 调用构造方法 通过配置文件 为成员变量赋值
1.开发步骤
- 提供有参构造方法
public class Customer implements Serializable {
private Integer id;
private String name;
public Customer(Integer id, String name) {
this.id = id;
this.name = name;
}
}
- Spring的配置文件
12333
bugz
2.构造方法重载
2.1 参数个数不同时
通过控制标签的数量进行区分
2.2 构造参数个数相同时
通过在标签引入type属性 进行类型的区分
**3.注入的总结
未来实战种,应用set注入还是构造注入?
答案:set注入更多
1.构造注入麻烦(重载)
2. Spring框架底层 大量运用了set注入
七、 反转控制与依赖注入
1.反转控制(IOC Inverse of Control)
控制:对于成员变量赋值的控制权
反转控制:把对于成员变量的赋值的控制权,从代码中反转(转移)到Spring工厂和配置文件中完成
好处:解耦合
底层实现:工厂模式
2.依赖注入
注入:通过Spring的工厂及配置文件,为对象(bean,组件)的成员变量赋值
依赖注入:当一个类需要另一个类时,就意味着依赖,一旦出现依赖,就可以把另一个类作为本类的成员变量,最终通过Spring配置文件进行注入(赋值)。
八、Spring工厂创建复杂对象
1.什么是复杂对象
复杂对象:指的就是不能直接通过new构造方法创建的对象
Connection
SqlSessionFactory
2.Spring工厂创建复杂对象的3种方式
2.1 FactoryBean接口
- 开发步骤
1) 实现FactoryBean接口
2)Spring 配置文件的配置
- 细节
1)如果想要获取复杂对象实现类本身的对象 需要这样获取
applicationContext.getBean("&conn", ConnFactoryBean.class)
在第一个参数"&XXX" 加一个&符号
2)isSingleton方法
返回 true 只会创建一个复杂对象
返回 false 每次都会创建一个新的复杂对象
问题:根据这个对象的特点,决定是返回true(SqlSessionFactory)还是false(Connection)
3)mysql高版本链接创建时,需要制定SSL证书,解决问题的方式
jdbc:mysql://localhost:3306/log?useSSL=false
4)依赖注入体会(DI)
- FactoryBean的实现原理(简易版)
基于接口回调
1、为什么Spring规定FactoryBean接口 实现 并且 getObeject()?
2、ctx.getBean(“conn”) 获得是复杂对象 Connection 而没有 获得 ConnectionFactoryBean(&)
Spring内部运行流程
1、通过conn获得 CnnectionFactoryBean类的对象,进而通过instanceof 判断出是FactoryBean接口的实现类
2、Spring按照规定 getObject —>Connection
3、返回Connection
- FactoryBean总结
Spring中用于创建复杂对象的一种方式,也是Spring原生提供的,后续讲解Spring整合其它框架时会大量应用FactoryBean
2.2 实例工厂
1、避免Spring框架的侵入
2、整合遗留系统
- 开发步骤
public class ConnectionFactory {
public Connection getConnection(){
Connection connection=null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/log?useSSL=false","root","123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
}
2.3 静态工厂
- 开发步骤
public class StaticConnectionFactory {
public static Connection getConnection(){
Connection conn=null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/log?useSSL=false", "root", "123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return conn;
}
}
3.Spring工厂创建对象的总结
九、控制Spring工厂创建对象的次数
1.如何控制简单对象的创建次数
使用scope标签内属性
singleton:只会创建一次简单对象 默认值
prototype:每次都会创建新的对象
2.如何控制复杂对象的创建次数
FactoryBean{
public Boolean isSingleton(){
return true; 只会创建一次
return false; 每一次都会创建新的
}
}
如果没有isSingleton方法 还是通过scope属性 进行对象创建次数的控制
3.为什么要控制对象的创建次数?
好处:节省不必要的内存浪费
- 什么样的对象之创建一次?
(1)SqlSessionFaction
(2)DAO
(3)Service
。。。
- 什么样的对象每一次都要创建新的?
(1)Connection
(2)SqlSession | Session
(3)Struts2 中的Action
。。。



