文章目录
引言
EJB(Enterprise Java Bean)存在的问题:EJB 是重量级的框架。
1.运行环境苛刻
2.代码移植性差
什么是spring?
Spring是一个轻量级的JavaEE解决方案,整合众多优秀的设计模式
- 轻量级
1.对于运行环境是没用额外要求的
开源 tomcat resion jetty
收费 weblogic websphere
2.代码移植性高
不需要实现额外接口
-
JaveEE解决方案
-
整合设计模式
1.工厂
2.代理
3.模块
4.策略
- 什么是设计模式
1.广义概率
面向对象设计中,解决特定问题的经典代码
2.狭义概念
GOF4人帮定义的23种设计模式:工厂,适配器,装饰器门面,代理,模块......
工厂设计模式
什么是工厂设计模式?
1.概念: 通过工厂雷,创建对象
User user=new User();
UserDao userDAO=new UserDAOImpl();
2.好处:解耦合
耦合:指定是代码间的强关联关系,一方的改变会影响到另一方
问题:不利于代码维护
简单:把接口的实现类,硬编码在程序中(耦合)
UserService userService=new UserServiceImpl();
简单工厂的设计
package com.xianxain.day01;
import java.io.*;
import java.util.Properties;
//工厂类
public class BeanFactory {
//创建properties集合
private static Properties env=new Properties();
private static Class classz= null;
static {
// //第一步 获取IO输入流
// File file = new File("src/main/resources/appcontext.properties");
// InputStream in = new FileInputStream(file); 或者以下操作
InputStream resourceAsStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
try {
//第二步 文件内容 封装 Properties集合中 Key=userService value=com.xianxain.day01.UserServiceImpl
env.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
//关闭流
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 工厂方法
* @return
* 对象的创建方式:
* 1.直接调用构造器 创建对象 UserService = new UserServiceImpl()
* 2.通过反射的形式 创建对象 解耦合
* Class classz=Class.forName("com.xianxian.day01.UserServiceImpl")
* UserService userService=(UserService)classz.newInstance();
*/
public static UserService getUserService(){
//但这种方式还是有耦合 所以通过反射
// return new UserServiceImpl();
// 反射
// Class classz= null;
// UserService userService=null;
// try {
// classz = Class.forName("com.xianxian.day01.UserServiceImpl");
// userService=(UserService) classz.newInstance();
// } catch (ClassNotFoundException e) {
// e.printStackTrace();
// } catch (InstantiationException e) {
// e.printStackTrace();
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// }
UserService userService=null;
try {
//通过Properties的key获取value
classz = Class.forName(env.getProperty("userService"));
userService=(UserService) classz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userService;
}
public static UserDao getUserDao(){
UserDao userDao=null;
try {
classz =Class.forName(env.getProperty("userDao"));
userDao=(UserDao)classz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userDao;
}
}
- 配置文件applicationContext.properties
# Properties 集合 存储 Properties文件的内容
#特殊Map key=String value=String
#Properties [UserService=com.xianxain.day01.UserServiceImpl]
#Properties.getProperty("userService")
userService=com.xianxain.day01.UserServiceImpl
#userService=com.xianxain.day01.UserServiceImplNew
userDao=com.xianxain.day01.UserDAOImpl
通用工厂的设计
问题:简单工厂会存在大量的代码冗余
解决方案:通用工厂的代码:
//工厂类
public class BeanFactory {
//创建properties集合
private static Properties env=new Properties();
private static Class classz= null;
/**
* 通用工厂
* @param key 根据传入的对象 读取对应的配置文件中key的值
* @return 进行返回
*/
public static Object getBean(String key){
Object object=null;
try {
classz=Class.forName(env.getProperty(key));
object=classz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return object;
}
}
通过工厂的使用方式
1.定义类型(类)
2.通过配置文件的配置告知工厂(applicationContext.properties)
key=value
3.通过工厂获得类的对象
Object ret=BeanFactory.getBean("key")
总结
Spring本质: 工厂模式 为我们提供的工厂叫做ApplicationContext 以及配置文件:applicationContext.xml
第一个Spring小程序
环境搭建
依赖查询网站:https://mvnrepository.com/
配置Spring的jar包
# 在pom文件里面引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
Spring的配置文件
1.配置文件的放置位置: 任意位置 没有硬性要求
2.配置文件的命名 :没有硬性要求 但建议:applicationContext.xml
注意:应用Spring框架时,需要进行配置文件路径的设置
Spring的核心API
ApplicationContext
作用:Spring提供的ApplicationContext这个工厂,用于对象的创建
好处: 解耦合
ApplicationContext
接口类型
接口:屏蔽实现的差异
非web环境 :ClassPathXmlApplicationContext
例如:(main junit)
web环境 :XmlWebApplicationContext
为什么没有XmlWebApplicationContext?因为没有引入web还需要引入web
web依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
点击刷新.就出现了
重量级资源
ApplicationContext工厂的对象占用大量内存
不会频繁的创建对象 : 一个应用只会创建一个工厂对象
ApplicationContext工厂:一定是线程安全的(多线程并发访问)
程序的开发
1.创建类型
2.配置文件的配置 applicationContext.xm<bean id="id名称(要唯一性)" class="文件的全限定名"/>
3.通过工厂 获得对象
ApplicationContext (因为是单元测试所以用非web环境)
|- ClassPathXmlApplicationContext |
第一种方式:ApplicationContext ctx=new ClassPathXmlApplicationContext("配置文件的路径") 类型 名称=(类型)ctx.getBean("对应的Bean的id")
第二种方式(传入多个配置文件):
ApplicationContext ctx=new ClassPathXmlApplicationContext("配置文件的路径1","配件文件的路径2"......)
第三种方式(传入一个数组)
ApplicationContext ctx=new ClassPathXmlApplicationContext(new String[] {"配置文件的路径1","配置文件的路径2",.....})
细节分析
名称解析
Spring工厂创建的对象,叫做Bean或者组件(componet)
Spring工厂的相关的方法
@Test
public void text4{
ApplicationContext ctx=new ClassPathXmlApplicationContext("/applicationContext.xml");
//第一种getBean的重载
//类型 名称=(类型)ctx.getBean("对应的Bean的id");
Person person = (Person)ac.getBean("person");
//第二种getBean的重载 这种可以避免强制类型转换
//类型 名称=ctx.getBean("对应的Bean的id",对应类.class);
Person person1 = ac.getBean("person", Person.class);
//第三种getBean重载 需要注意的是:这种只能 配置文件中只有一个Bean 否则异常 (当前Spring的配置文件中,只能只有一个<bean class是唯一的 否则异常)
//类型 名称=ctx.getBean(对应类.Class);
Person bean = ac.getBean(Person.class);
//获取当前Spring配置文件中所有Bean标签(Bean定义)的id的值 返回的对象是一个String数组
String[] beanDefinitionNames=ctx.getBeanDefinitionName();
//进行遍历
for(String beanDefinitionName: beanDefinitionNames){
System.out.println("beanDeinitionName"+beanDeinitionName);
}
//根据指定的类型获取Spring配置文件中对应的Bean的名字(id的值)
String[] beanNameForTypes=ctx.getBeanNameForType(类型.class);
//进行遍历
for(String beanNameForType:beanNameForTypes){
System.out.println("beanNameForType"+beanNameForType);
}
//用于判断是否存在指定id值的Bean 返回的是boolean值 需要注意的是:只能判断id值 不能判断name值
if(ctx.contaibsBeanDefinition("id的值")){
System.out.println("True = "+true)
}else{
System.out.println("False = "+false)
}
//用于判断是否存在指定id值的Bean 返回的是boolean值 需要注意的是:id值和name值都是可以判断的
if(ctx.containsBean("id的值")){
System.out.println("True = "+true);
}else{
System.out.println("False = "+false)
}
}
配置文件中需要注意的细节
1.只配置class属性
<bean class="类的全限定名"/>
//1.上述这种配置 有没有 id 值 ?
//可以通过以上相关方法中获取id的值的方法进行获取
//可以得到一个"类全限定名#0"
//2.应用场景:如果这个bean只要用一次,那么就可以省略id值,
//反之如果这个bean使用多次或者被其他bean应用需要设置id值
2.name属性
作用:用于在Spring的配置文件中,为bean对象定义别名(小名)
相同的地方
1.ctx.getBean("id的值/name的值");//--->object
2. <bean id="" class=""
等效于
<bean name="" class=""
区别:
1.别名可以定义多个(以逗号分隔),但是id属性只能有一个值
<bean id="名称" name="名称1,名称2,名称3" class=""/>
2.XML的id属性的值,命名要求,必须要以字母开头,字母,数字,下划线,连字符 注意:不能以特殊字符开头
name属性的值,命名没有任何的要求
所以name属性会应用在特殊命名的场景下:
XML发展到了现在:ID属性的限制,不存在了 也可以反斜线命名了
3.代码区别
//用于判断是否存在指定id值的Bean 返回的是boolean值 需要注意的是:只能判断id值 不能判断name值
if(ctx.contaibsBeanDefinition("id的值")){
System.out.println("True = "+true)
}else{
System.out.println("False = "+false)
}
//用于判断是否存在指定id值的Bean 返回的是boolean值 需要注意的是:id值和name值都是可以判断的
if(ctx.containsBean("id的值")){
System.out.println("True = "+true);
}else{
System.out.println("False = "+false)
}
Spring工厂的底层实现原理(简易版)
思考
问题: 未来在开发过程中, 是不是所有的对象,都交给Spring工厂创建呢?
回答:理论上 是的,但是有特列 : 实体对象(entity)是不会交给Spring创建, 它是持久层框架进行创建(例如:Mybatis)
Spring5.x与日志框架的整合
Spring与日志框架进行整合,日志框架就可以在控制台中,输出Spring框架运行过程中的一些重要的信息
好处:便于了解Spring框架的运行过程,利于程序的调试
Spring如何整合日志框架
默认
Spring1.2.3早期都是于commons-loggin.jar
Spring5.x默认整合的日志框架 logback log4j2
Spring5.x整合log4j
1.引入log4j jar包
2.引入log4.properties配置文件
- 在pom文件中引入依赖
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>2.0.0-alpha1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 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 H:mm:ss} %-5p %c{1}:%L- %m%n
测试
这样就表示成功了