Spring工厂详解
第一章 引言
1.1 EJB存在的问题
EJB(Enterprise Java Bean)主要存在两个问题:
- 运行环境苛刻;
- 代码移植性差。
总结:EJB是一个重量级的框架。
1.2 什么是Spring
Spring是一个轻量级的JavaEE解决方案,整合了众多优秀的设计模式。
-
轻量级:
- 对于运行环境是没有额外要求的:
- 开源 tomcat resion jetty
- 收费 weblogic websphere
- 代码移植性高
- 不需要实现额外的接口
- 对于运行环境是没有额外要求的:
-
JavaEE的解决方案:
Spring对于JavaEE开发中的各层(Controller、Service、Dao)都有相应的解决方案。
-
整合设计模式:
- 工厂设计模式
- 代理设计模式
- 模板设计模式
- 策略设计模式
1.3 设计模式
- 广义概念:面向对象设计中,解决特定问题的经典代码;
- 狭义概念:GOF4人帮定义的23种设计模式:工厂、适配器、装饰器、门面、代理、模板…
1.4 什么是工厂设计模式
-
概念:通过工厂类,创建对象:
-
好处:解耦合
-
耦合:指的是代码之间的强关联关系,乙方的改变会影响到另一方。
-
问题:不利于代码的维护。
-
简单的理解为:把接口的实现类,硬编码再程序中:
UserService userService = new UserServiceImpl();
-
1.5 简单的工厂设计模式
在applicationContext.properties中编写相关类名与类路径的对应关系:
userService = com.itheima.basic.UserServiceImpl
userDao = com.itheima.basic.UserDaoImpl
定义简单的工厂类:
public class BeanFactory {
private static Properties env = new Properties();
//使用静态代码块,在对象创建时初始化加载相关配置文件
static{
InputStream inputStream = null;
try {
inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
env.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
对象的创建方式:
1.直接调用构造方法,创造对象:UserService userService = new UserServiceImpl();
2.使用反射的方式,创建对象,解耦合:Class.forName("全限定类名");
*/
public static Object getBean(String className){
Object object = null;
try {
Class aClass = Class.forName(env.getProperty(className));
object = aClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return object;
}
}
测试类中利用BeanFactory工厂类获取对象:
@Test
public void test01(){
// UserService userService = new UserServiceImpl();
//使用工厂类创建对象,替代传统的new创建对象,解耦合
UserService userService = (UserService) BeanFactory.getBean("userService");
userService.login("name","suns");
User user = new User("user","123456");
userService.register(user);
}
对于UserServiceImpl中的UserDao成员变量:
private UserDao userDao =(UserDao) BeanFactory.getBean("userDao");
-
通用工厂的的使用方式:
-
定义类;
-
通过配置文件的配置告知工厂(applicationContext.properties)
- key(类名)=value(全限定类名)
-
通过工厂获得类的对象
-
UserService userService = (UserService) BeanFactory.getBean("userService");
-
-
1.6 总结
Spring本质:工厂、ApplicationContext(ApplicationContext.xml)
第二章 第一个Spring程序
2.1 环境搭建
-
Spring的jar包:
<dependencies> <!-- Spring的应用上下文依赖: 其中还依赖了:spring-aop、spring-beans、spring-core、spring-expression、spring-jcl --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.9.RELEASE</version> </dependency> </dependencies>
-
Spring的配置文件:
- Spring配置文件放置的位置:可以放在任意位置;
- Spring配置文件的命名:可以任何名字,建议叫做:applicationContext.xml
2.2 Spring的核心API
-
ApplicationContext:
作用:Spring提供的ApplicationContext这个工厂,用于对象的创建。
好处:解耦合
-
ApplicationContext接口类型:
接口:屏蔽实现的差异
主要有两种实现:
- 非WEB环境:ClassPathXmlApplicationContext
- WEB环境:XmlWebApplicationContext
-
重量级资源:
ApplicationContext工厂的对象占用大量的内存,不会频繁的创建这个对象,一个应用只会创建一个工厂对象,所以ApplicationContext可以被并发访问,一定是线程安全的。
2.3 程序开发
- 创建类型
- 配置文件的配置ApplicationContext.xml
- 通过工厂类,获得对象:这里使用ApplicationContext的一个实现类:ClassPathXmlApplicationContext
-
创建一个Person类;
-
在ApplicationContext.xml配置该类型:
<!-- id属性:名字,唯一; class属性:配置全限定类名 --> <bean id="person" class="com.itheima.basic.Person"/>
-
在测试类中,使用ClassPathXmlApplicationContext类加载配置文件,并通过该类的类对象创建配置文件中配置的类的对象:
/** *用于测试Spring的第一个程序 */ @Test public void test02(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Person person = context.getBean("person", Person.class); System.out.println(person);//com.itheima.basic.Person@9a7504c }
2.4 细节分析
-
名词解释:
Spring工厂创建的对象,叫做bean或者组件(component)
-
Spring工厂的相关方法:
- getBean方法的三种重载方式:
- getBean(“person”):创建id=“person”的对象,此方法创建的是Object’对象,需要强转为响应类型的对象;
- getBean(“person”,Person.class):创建创建id=“person”的Person类型的对象;
- getBean(Person.class):创建类型为Person的对象,此方法要求配置文件中类型为Person的bean标签只能有一个。
- getBeanDefinitionNames:获得所有bean标签的id属性值(或name属性值)
- getBeanNamesForType:获得某种类型的bean的id属性值
- containsBean:判断是否有指定id值的bean
- containsBeanDefinition:判断是否有指定id值的bean
- getBean方法的三种重载方式:
-
Spring配置文件的细节:
- 只配置class属性,而不配置id属性,这时候Spring会为这个bean提供一个id值,如: com.itheima.basic.Person#0。
- 应用场景:如果这个bean只需要使用一次,那么就可以省略id值。
- name属性:
- 作用:用于在Spring的配置文件中,为bean对象定义别名。
- 与id属性的不同之处:别名可以定义多个,多个别名间以逗号相隔。
- 只配置class属性,而不配置id属性,这时候Spring会为这个bean提供一个id值,如: com.itheima.basic.Person#0。
2.5 Spring工厂的底层实现原理(简易版)
-
通过ClassPathXmlApplicationContext工厂读取配置文件applicationContext.xml
-
获取bean标签的相关信息,如:
- id的值=person
- class的值=com.itheima.spring.domain.Person
-
通过反射创建对象,如:
Class clazz = Class.forName("com.itheima.spring.domain.Person"); Person person = (Person)clazz.newInstance();
-
反射创建对象,其实底层还是构造方法创建对象:
Person person = new Person();
细节:
- 如果这个类的构造方法是私有的,那么Spring也会调用这个类的构造方法创建对象,这是因为反射可以调用私有方法.
思考:
- 问题:未来在开发过程中,是不是所有的对象,都会交给Spring工厂来创建对象呢?
- 答案:理论上来说是的,但是有特例:实体对象(entity)是不会交给Spring来创建的,它是由持久层框架来创建的.
第三章 Spring与日志框架的整合
Spring与日志框架进行整合,日志框架就可以在控制台中,输出Spring框架运行过程中的一些重要的信息.
好处:便于了解Spring框架的运行过程,利于程序的调试.
- Spring如何整合日志框架:
- Spring 1\2\3 早期都是与commons-logging.jar
- Spring5.x默认整合的日志框架logback\log4j
3.1 Spring5.x整合log4j
- 引入log4j的jar包
- 引入log4j.properties配置文件
-
pom:
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</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{ABSOLUTE} %5p %c{1}:%L - %m%n
第四章 注入(Injection)
4.1 什么是注入
通过Spring的工厂及配置文件,为所创建的对象的成员变量赋值.
-
为什么需要注入:通过编码的方式,为成员变量进行赋值,存在耦合:
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml"); Person person1 = context.getBean("person1",Person.class); //通过代码为成员变量赋值,存在耦合 person1.setId(1); person1.setName("小王"); System.out.println(person1);
-
如何进行注入:
-
类为成员变量提供get\set方法;
-
配置Spring的配置文件:
<bean id="person1" class="com.itheima.basic.Person"> <property name="id" > <value>1</value> </property> <property name="name"> <value>suns</value> </property> </bean>
-
4.2 Spring注入的原理分析(简易版)
- Spring通过底层调用对象属性对应的set方法,完成成员变量的赋值,这种方法成为Set注入:
<bean id="person1" class="com.itheima.basic.Person">
等效于
Person person1 = new Person()