零、说明
本教程为记录B站Spring孙哥的笔记,想看视频的朋友可以去看看。
二、EJB框架
Spring框架是为了解决javaEE规范中EJB框架的缺陷而衍生的,那么EJB到底有什么缺陷呢?
首先EJB的全称为Enterprise Java Bean,他的缺陷在于,第一,运行环境苛刻;第二,代码移植性差
为什么运行环境苛刻呢?首先02年左右的服务器有像weblogic和websphere 这些应用服务器(ApplicationServer),他们都是收费的,并且这些容器的复杂度比Tomcat的要大,同时最坑爹的一点就是,在webLogic容器的EJB代码要实现WebLogic的规定的接口才能部署上去,而如果想部署在weblogic的代码转移到websphere上面,则是不行的,所有说它的代码移植性差;对了,EJB框架的代码是要部署到EJB容器中,然后再将EJB容器部署到对应的applicationServer服务器上才能部署成功;
而Spring就不一样了,它部署在tomcat上面,tomcat作为web服务器,它的复杂程度远没有上述的两个容器大,spring的代码的灵活性比较强,能够灵活地扩展其他不同的框架,而且可以部署在不同的web服务器上
三、什么是Spring?
Spring是一个轻量级的javaEE的解决方案,其高度整合了众多设计模式
- 轻量级
1> 对于运行环境没有额外的要求,它可以运行在下面的任何一个服务器上
开源:tomcat、resion、jetty
收费: weblogic、websphere
2> 代码移植性高
不需要实现额外接口
- javaEE的解决方案
我们说javaEE的开发是分层操作的,主要分为Controller、Service、DAO、DB
但是想Struts2只能解决Controller层的问题,Mybaits只能解决DAO层的问题,
但是Spring不同,它更像一个胶水框架,在各个层都有很好的封装,下面为其对应的解决
关系
SpringMVC ---》 Controller
AOP ---》 Service
JDBC、Hibernate ---》 DAO
- 整合了众多的设计模式
工厂模式
代理模式
模板模式
策略模式
1.广义的角度: 面向对象设计中,解决特定问题的经典代码
2.狭义的角度:GOF4人帮在很多年前在一本书上列巨的23种设计模式,
但是一个项目并非全部的设计模式都会涉及,毕竟有些还是桌面端开发
才会用到的;
4.2 工厂设计模式
4.2.1 什么是工厂设计模式
前言:之所以要使用工厂设计模式,这是因为工厂模式能很好地解决代码耦合的问题
概念: 通过工厂类,创建对象
好处:解耦
什么是耦合:指代码之间的强关联关系,一方的改变会影响另一方
我们知道每次发版,都是really heavy的, 所以我们希望寻求一个更通用和灵活的代码,
尽管一处改变,也不尽可能地不影响之前的调用
耦合的例子:把接口的实现类,硬编码在程序中
比如:
public Class HelloController{
(接口)UserService userService = (实现类)new UserServiceImpl();
}
如果实现类变了,那么HelloController整个方法的调用都要改变,这就涉及到改代码了
4.2.2 怎么使用工厂模式
4.2.2.1 实现一个简单的工厂模式
/*那么既然在上面的代码中产生了耦合,那么最简单的直接的解耦方式是什么呢?
我们定义个类,专门返回对应的实现类,那么在controller的方法里面就实现了
解耦,如下
1.定义一个工厂类 */
public class BeanFactory {
//直接返回接口
//下面这里使用了工厂方法,但是这里产生了耦合,那么这里的耦合该如何处理呢?
public static HelloSevice getService(){
return new HelloSeviceImpl();
}
}
//2.在Controller层通过工厂类返回实现类
@PostMapping("factorySolve")
public void factoryTest02(){
HelloSevice service = BeanFactory.getService();
service.login("paul","123");
User user = new User("小明", "456");
service.register(user);
}
4.2.2.2 上面的代码问题与解耦改进
在进入改进的话题之前,我们先来复习一下创建对象的方式包括哪些?
1>直接调用构造方法来创建对象,比如UserService userService = new UserServiceImpl();
用这种方式其实就会将创建这个对象的代码写死了,以后想换其他实现类就不行了,这种方式
明显不利于解耦
记住: 接口的存在本来就是为了解耦,要尽可能地使用其特性
2>通过反射的形式拿到对应的类对象,然后创建对象
比如: Class clazz = Class.forName("类的全限定名");
UserService userService = (UserService)clazz.newInstance();
使用这种方式的话,就能够说我想换另一个实现类,就是需要换那个全限定名即可
但是这里还是会有一点耦合,就是那个类的全限定名也是写死在代码上面的,那么
如何去优化呢?没错就是写配置文件!
4.2.2.3 进入改造实战
第一步:首先创建配置文件
第二步 改造工厂类
//为了避免频繁io,我们在使用static去修饰以实现一次性加载
private static Properties env = new Properties();
static {
try {
//获取io流对象(其实任何一个流都可以通过类对象获取io流),但是注意类似String,Integer这些貌似是不行的
InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
//加载进env对象内,这时候就实现了说env对象里面存放着类似map结构的数据
env.load(inputStream);
//关闭流对象,否则这个流的连接一直存在,最终会导致io负载过高的
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//下面为改造后的工厂类
public static HelloSevice getServiceUpdate(){
HelloSevice sevice = null;
//通过反射获取Class对象
Class clazz ;
try {
clazz = Class.forName(env.getProperty("userService"));//类的全限定名
sevice = (HelloSevice) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return sevice;
}
备注:通过上面的改造,如果下次我们希望换成其他实现类,那么只需将配置文件的全限定名更换即可
同样地,我们也可以去对Service使用DAO层的dao代码实现解耦
4.2.2.3 工厂类的方法再改造
1》重复的代码问题
问题描述: 通过上面的工厂代码,我们会发现一个问题,对于实现类我们通过反射+配置文件得到了对应的对象,对于Dao的实现类我们又通过反射+配置文件的方式得到对应的对象,那么如果有很多其他不同的接口的实现类为了解耦,那岂不是要同样地写很多重复的代码?所以,我们需要去重构他们,
那么他们有什么共同点吗?其实是有的,你看是不是都是通过反射获取对象啊?是不是都传入一个“标识"来动态获取实现类呢?所以我们完全可以再改造他们,如下面的代码
public class BeanFactory(){
//对于工厂方法的再改造,我们把这个方法叫通用工厂方法
//我们发现上面的代码也存在着大量的冗余,所以我们需要进一步地解耦
public static Object getBean(String name){ //通过外部传入标识
Object ret = null;
try {
Class clazz = Class.forName(env.getProperty(name));
ret= clazz.newInstance();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return ret;
}
}
4.3 通用工厂的使用方式小结
1>定义类型(类),就是说我们需要一个将要被创建的目标类
2>通过配置文件的配置来告知工厂(application.properties)
通过key = value的形式在配置文件声明
3>通过工厂获取类的对象(注意转换)
Object ret = BeanFactory.getBean("key");
4.4 总结
上面说了这么多关于工厂设计模式,其实都是为了说明一个事实
Spring的本质就是工厂,只不过它的功能比我们的demo更强大罢了
它的工厂类叫 ApplicationContext,它的配置文件为 applicationContext.xml