EJB
EGB运行环境苛刻,造价高昂,代码扩展性差,移植性差,被视为重量级框架。

weblogic和websphere作为收费且不开源的应用服务器,许多中小型企业无法使
用,且无法进行定制和修改。
Spring?

spring是一个轻量级的javaee解决方案,整合众多优秀的设计模式
1.轻量级
1.对于运行环境没有要求
tomcat resion jetty 开源
weblogic websphere 收费
2.代码移植性高
不需要额外接口
2.javaee解决方案
3.整合设计模式
工厂 代理 模板 策略
设计模式
1.广义概念
面向对象设计中,解决特定问题的经典代码
2,狭义概念
gof4人帮定义的23种设计模式:工厂 式:工厂,适配器,装饰器,门面,代理,模板。
工厂设计模式
1.通过工厂类进行创建对象
传统方式创建对象
User user = new User();
UserDao userDao = new UserDaoImpl
2.好处:解耦合
耦合:指定的是代码间的强关联关系,一方的改变会影响到另一方.
问题:不利于代码的维护
简单:接口的实现类硬编码在程序中

简单的工厂设计模式
会存在大量代码冗余


通用的工厂设计模式
可以创建一切想要创建的对象

通用的工厂的使用方式
1.定义类型 (类)
2.通过配置文件的配置来告诉工厂(applicationContext.properties)
key=value
3.通过工厂获得类的对象 Object ret = BeanFactory.getBean(key);
总结:
spring本质:工厂 ApplicationContext.xml
spring环境搭建
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
1.配置文件的放置位置:任意位置 没有硬性要求
2.配置文件的命名:没有硬性要求 建议使用 applicationContext.xml
spring的核心API
ApplicationContext
1.作用 spring提供的ApplicationContext这个工厂,用于对象的创建
2.好处:解耦合
ApplicationContext接口类型
1.接口:屏蔽实现的差异
2.非web环境: ClasspathXmlApplicationContext (main junit)
3.web环境: XmlApplicaitonContext
重量级资源
1.ApplicationContext工厂的对象占用了大量的内存资源。因此不能够频繁的创建对象,一个应用程序只会创建一个内存对象
2.ApplicaitonContext工厂:一定是线程安全的。
程序开发
1.创建对象
2.配置文件的配置 applicationContext.xml
id 唯一 class 全限定名称
3.通过工厂类,获得对象
ApplicationContext
ClasssPathXmlApplicationContext
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
// 当前spring配置文件中只能有一个Person类型 否则会抛出异常
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
细节分析
spring工厂创建的对象叫做bean或者组件component
@Test
public void test02() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
// 获得spring配置文件中所有的id值
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
//根据类型获取spring配置文件中所有对应的id值
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String beanName : beanNamesForType) {
System.out.println(beanName);
}
//判断是否存在id为person的bean
boolean person1 = ctx.containsBean("person");
//判断是否存在id或者name为person的bean
boolean person11 = ctx.containsBeanDefinition("person1");
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
}
配置文件需要注意的细节
-
只配置class属性
上述这种配置 有没有id值 默认:beanDefinitionName = com.baizhi.basic.Person#0
应用场景: 如果这个bean只需要使用一次的话,那么就可以省略id值
如果这个bean回事哟个多次,或者被其他的bean引用 则需要设置id值
- name属性
作用:用于在spring配置文件中,为bean对象定义别名(小名)
相同:1.Person p = ctx.getBean(“p”, Person.class);
2.
区别:别名可以定义多个 ,但是id只能有一个
xml id属性值,命名要求:必须以字母开头,字母 数字 下划线 连字符,但是发展到今天,没有了限制
name属性值之没有任何要求的 应用在特殊的场景下
3.代码
//判断是否存在id为person的bean
boolean person1 = ctx.containsBean("person");
//判断是否存在id或者name为person的bean
boolean person11 = ctx.containsBeanDefinition("person1");
spring工厂底层实现原理简易版

未来在开发的过程中,是不是所有的对象都可以交给spring工厂进行创建的?
理论上:是的 但是有特例:实体对象(entity)对应着数据库中的数据,由持久层框架进行创建。
spring与日志框架整合
spring与日志框架进行整合可以在控制台中输出spring框架运行过程中的一些重要的信息
好处:可以了解spring框架的运行过程,利于程序的调试
整合log4j:
1.引入jar
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.引入log4j.properties
# resources # 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
注入
1.什么是注入?
通过spring工厂及配置文件,为所创建对象的成员变量进行赋值
2.为什么需要注入
通过编码的方式为对象进行赋值,会造成耦合。

开发步骤
1.为类对象提供set get方法
2.配置spring的配置文件
<bean id="person" name="p,p1,p2" class="com.baizhi.basic.Person">
<property name="id" value="1"></property>
<property name="name" value="yangShen"></property>
</bean>
3.注入的好处:解耦合
spring注入原理分析的简易版
Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方式我们称之为set注入。

set注入

JDK内置
1.String+八种基本数据类型
2.数组
<list>
<value>1020917713@qq.com</value>
<value>1020912313@qq.com</value>
<value>1043912313@qq.com</value>
</list>
3.set集合
<set>
<value>123</value>
<value>1234</value>
<value>12345</value>
</set>
<set>
<ref bean=>
</set>
4.list集合
<list>
<value>1020917713@qq.com</value>
<value>1020912313@qq.com</value>
<value>1043912313@qq.com</value>
<ref bean= ></ref>
</list>
5.map集合
map — entry – key由特定的标签
值根据特定的类型选择对用类型的标签
<entry>
<key><value>yangShen</value></key>
<value>1020917713</value>
</entry>
<entry>
<key><value>yangAo</value></key>
<value>2390596320</value>
<ref bean=>
</entry>
6.Properties
特殊的map key value 都是String 类型
<property name="properties">
<props>
<prop key="key1">yangshen</prop>
<prop key="key2">yangao</prop>
</props>
</property>
用户自定义类型
1.第一种方式
<bean id="userService" class="xxx.UserServiceImpl">
<property name="userDao">
<bean class="xxx.UserDaoImpl"></bean>
</property>
</bean>
存在的问题:1.配置文件的冗余 2.被注入的对象多次创建,浪费jvm资源。
2.第二种方式
<bean id="userDao" class="xxx.UserDaoImpl"></bean>
<bean id="userSerice" class="xxx.UserviceImpl">
<property name="userDao">
<ref bean="userDao"></ref>
</property>
</bean>
spring4.x 废除了 <ref local=""/> 基本等效 <ref bean=""></ref>
set注入简化写法
1.重要
<property name="name" value=""></property>
<property name="name" ref=""></property>
2.基于p命名空间简化 了解即可
<bean id="person" class="com.baizhi.basic.Person" p:name="yangShen"></bean>
构造注入
开发步骤:
1.提供有参构造方法
public class Customer implements Serializable {
private String name;
private int age;
public Customer() {}
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Customer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.spring的配置文件
<bean id="customer" class="com.baizhi.basic.constructor.Customer">
<constructor-arg>
<value>yangShen</value>
</constructor-arg>
<constructor-arg>
<value>12</value>
</constructor-arg>
</bean>
构造方法的重载,如何进行注入?
<constructor-arg type="java.lang.String"></constructor-arg>
反转控制(IOC)
控制:对于成员变量赋值的控制权
反转控制:把成员变量赋值的控制权,从代码转移到spring的工厂和配置文件中。底层原理:工厂设计模式

依赖注入
当一个类需要另一个类的时,就意味着依赖,一旦出现依赖,就可以把另外一个类作为本类的成员变量,最终通过spring工厂和配置文件进行注入(赋值)

什么是复杂对象?

spring工厂创建复杂对象的三种方式
1.FactoryBean接口
开发步骤:
1.实现FactoryBean接口
public class ConnectionFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection("jdbc:mysql:///db", "root", "1234");
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
}

2.Spring配置文件的配置
# 如果Class中指定的类型是FactoryBean接口的实现类,那么通过id值获得的是这个类所创建的复杂对象
<bean id="conn" class="com.baizhi.basic.factorybean.ConnectionFactoryBean"></bean>

细节:
1.如果就像获得FactoryBean对象的话,写ctx.getBean(“&conn”);
2.isSingleton 返回true的时候 创建一个复杂对象 反之 则会创建多个对象
3.mysql高版本连接的时候,需要指定SSL证书,解决的方式为:
url="jdbc:mysql://localhost:3306/db?useSSL=false"
2.实例工厂
1.避免spring框架的侵入 防止过度依赖
2.整合遗留系统
public class ConnectionFactory {
public Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///db", "root", "1234");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
<bean id="connFactory" class="com.baizhi.basic.factorybean.ConnectionFactory"></bean>
<bean id="conn" factory-bean="connFactory" factory-method="getConnection"/>
3.静态工厂
public class ConnectionStaticFactory {
public static Connection getConnection() {
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql:///db", "root", "1234");
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
<bean id="conn" class="com.baizhi.basic.factorybean.ConnectionStaticFactory" factory-method="getConnection"></bean>
总结:
Singleton
对象只会创建一次

Prototype
每一次创建新的对象

对象的生命周期
一个对象创建 存活 消亡的整个过程
生命周期的三个阶段:
1.创建阶段
Spring工厂何时创建对象?
scope=“singleton”
工厂创建的时候同时创建对象,
如果不想要工厂创建的同时实例化对象,只需要加:
lazy-init="true"
scope=“prototype”
只有当获取ctx.getBean()的时候才能创建对象
2.初始化阶段
spring工厂在创建完对象的时候,调用对象的初始化方法,完成初始化的操作
初始化操作是对资源的初始化 例如 数据库 io 网络
1.初始化方法是由程序员根据需求来提供的
2.初始化方法是由spring工厂来进行调用的
实现方法
第一种方式:实现InitializingBean接口
第二种方法:提供一个普通的方法,只需要在配置文件中进行配置就可以了 因为要告诉spring
init-method="afterPropertiesSet"
细节分析:
如果一个对象既实现了InitializingBean接口,由提供了普通的初始化方法,顺序为:执行接口中的方法在去执行普通方法
创建对象 属性注入 初始化 使用 销毁
3.销毁阶段(只适用在singleton中)
spring销毁对象前 会调用对象的销毁方法 完成销毁操作(资源的释放) 工厂关闭前进行销毁操作
第一种方式:实现DisposableBean接口
@Override
public void destroy() throws Exception {
}
第二种方法:提供一个普通的方法,只需要在配置文件中进行配置就可以了 因为要告诉spring
destroy-method=""
- 细节分析:
如果一个对象既实现了DisposableBean接口,由提供了普通的初始化方法,顺序为:执行接口中的方法再去执行普通方法
创建对象 属性注入 初始化 使用 销毁
配置文件参数化
把spring配置文件中需要经常修改的字符串转移到更小的配置文件当中


自定义类型转换器
spring通过类型转换器把配置文件中的字符串类型的数据,转换成对象中成员变量对应类型的数据,进而完成了注入。

为什么需要类型转换器?
当spring内部没有提供特定类型的转换器时,而程序员在应用过程中还需要使用,那么就需要程序员自己定义类型转换器。
1.自己编写一个类实现Converter接口
public class MyConverter implements Converter<String, Date> {
/**
*
* @param source 代表配置文件中的字符串 也就是你需要转换的东西
* @return spring自动会把转换完成的东西赋值
*/
@Override
public Date convert(String source) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = simpleDateFormat.parse(source);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
2.告诉spring
<!-- 创建converter类型转换器-->
<bean id="myConverter" class="com.baizhi.basic.convert.MyConverter"></bean>
<!-- 注册类型转换器 conversionService必须叫这个 大小写也必须是这样-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="conversionService"></ref>
</set>
</property>
</bean>
后置处理bean
BeanPostProcessor:对spring工厂所创建的对象,进行再加工

程序员实现接口中的方法即可,spring会自动调用该方法
实战当中很少使用,仅仅了解就ok了
细节:BeanPostProcessor会对spring工厂中所有创建的对象进行加工。

173

被折叠的 条评论
为什么被折叠?



