1.工厂设计模式
1.1 简单工厂
设计核心(工厂)
public class BeanFactory {
/*
class Properties extends Hashtable<Object,Object> 继承于hashtable
*/
//创建一个Properties集合
private static Properties env = new Properties();
//使用静态代码块保证Properties只创建一次
static {
try {
//1.获得文件输入流
InputStream inputStream = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
//2.将文件内容读入env中
//load() 从输入字节流中读取属性列表(键和元素对)
env.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*
对象创建方式:
1.使用构造器创建对象
2.使用反射创建对象(解耦合)
*/
public static UserService getUserService(){
//return new UserServiceImpl();
UserService userService = null;
try {
//Class<?> clazz = Class.forName("com.xxc.basic.UserServiceImpl");
Class<?> clazz = Class.forName(env.getProperty("userServices"));
userService = (UserService)clazz.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 {
//Class<?> clazz = Class.forName("com.xxc.basic.UserDAOImpl");
Class<?> clazz = Class.forName(env.getProperty("userDAO"));
userDAO = (UserDAO)clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return userDAO;
}
}
UserService接口
public interface UserService {
void register(User user);
void login(String name,String password);
}
UserService具体实现类
使用工厂解耦合
public class UserServiceImpl implements UserService {
//private UserDAO userDAO = new UserDAOImpl();
private UserDAO userDAO = BeanFactory.getUserDAO();
@Override
public void register(User user) {
userDAO.save(user);
}
@Override
public void login(String name, String password) {
userDAO.queryUserByNameAndPassword(name, password);
}
}
UserDAO接口
public interface UserDAO {
void save(User user);
void queryUserByNameAndPassword(String name,String password);
}
UserDAO接口的实现类
public class UserDAOImpl implements UserDAO{
@Override
public void save(User user) {
System.out.println("insert into user = "+user);
}
@Override
public void queryUserByNameAndPassword(String name, String password) {
System.out.println("query User name = "+name+" password = "+password);
}
}
测试方法
@Test
public void Test01(){
//UserService userService = new UserServiceImpl();
//使用工厂模式解耦合
UserService userService = BeanFactory.getUserService();
userService.login("name","xxc");
User user = new User("xxc", "123456");
userService.register(user);
}
配置文件applicationContext.properties
# properties集合存储文件内容
# 是一种特殊的Map key=String value=String
userServices = com.xxc.basic.UserServiceImpl
userDAO = com.xxc.basic.UserDAOImpl
1.2通用工厂
反思:
工厂方法中getUserService()和getUserDAO()中代码存在大量冗余,只有返回值类型,forname()中内容不同
因此就可以抽离出以下通用代码
public static Object getBean(String key){//key就是小配置文件中的key值
Object o = null;
try {
Class<?> clazz = Class.forName(env.getProperty(key));
o = clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return o;
}
1.3通用工厂的使用方式
1. 定义类
2. 通过配置文件告知工厂想要创建那个对象(application.properties)
key = value
3. 通过工厂获得类的对象
BeanFactory.getBean("key");
例:
1. 创建类
public class Person {}
3.使用
@Test
public void Test02(){
Person person = (Person)BeanFactory.getBean("person");
System.out.println(person);
}
#2. 在配置文件中添加
person = com.xxc.basic.Person
2.第一个Spring程序
1.下载网址
www.spring.com
maven环境搭建
- spring的jar包
maven下载地址:https://mvnrepository.com/search?q=spring
# 设置pom依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.4.RELEASE</version>
</dependency>
- spring的配置文件
1. 配置文件放置位置:任意位置,没有硬性要求
2. 命名:没有硬性要求,建议:applicationContext.xml
在应用spring时,需要进行配置文件路径配置
2.spring的核心api
ApplicationContext
好处: 使用spring提供的ApplicationContext工厂创建对象,用于解耦合
ApplicationContext接口类型
屏蔽接口实现的差异
非web环境下:ClassPathXmlApplicationContext
web环境:XmlWebApplicationContext
重量级资源
ApplicationContext工厂的对象会占用大量资源
因此不会频繁创建,即一个应用只会创建一个工厂对象
所以也就要求ApplicationContext工厂一定是线程安全的,能够支持多线程访问
3.程序开发
1. 创建类型
2. 配置文件配置
3. 通过工厂类获得对象
ApplicationConText ctx = new ClassPathXmlApplicationContext("/application.xml");
Person person = (Person)ctx.getBean("person");
4.细节分析
spring工厂的相关方法
@Test
public void Test04() {
//1.获得spring工厂对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
//2、通过工厂获得对象
//Person person = ctx.getBean("person", Person.class);
/*
//使用这种方式创建时,需要注意,applicationContext.xml需要保证在配置文件中,只能有一个bean中class是Person
Person person = ctx.getBean(Person.class);
System.out.println(person);
*/
//返回此工厂定义的所有bean名称(<bean id="">id后引号中的值)
//String[] names = ctx.getBeanDefinitionNames();
//返回此工厂中给定类型的名称
// String[] names = ctx.getBeanNamesForType(Person.class);
// for (String name : names) {
// System.out.println(name);
// }
//判断是否存在指定id的bean,存在返回true
// boolean person = ctx.containsBeanDefinition("a");
//判断是否存在指定id的bean
boolean person = ctx.containsBean("person");
System.out.println(person);
}
配置文件中需要注意的细节
1. 只配置class标签
<bean class = ""/>
a) 使用上面这种配置有没有id值?
com.xxc.basic.User#0
b) 应用场景: 如果这个bean只使用一次,那么就可以省略id值
如果这个bean只使用多次,或者被其他bean引用则需要设置id值
2. name属性
作用:用于在spring的配置文件中,为bean对象设置别名
id与name对比:
相同:
1.ctx.getBean("id/name");
2.<bean id="" class=""
等效
<bean name="" class=""
区别:
1.别名可以定义多个,但是id属性只能定义一个
2.XML的id属性值命名要求:必须以字母开头,后面跟字母,数字,下划线,连字符,不能以特殊字符开头
name属性的值,没有命名要求
name属性会应用于特殊场景
不过XML发展到今天,就没有了这些限制
3.代码区别
containBean可以用来判断id,也能判断name
containBeanDefintion可以用来判断id,但是不能用于判断name
5.spring工厂的底层实现原理(简易)
spring工厂是可以调用是由构造器的
6.思考
问题:在开发过程中,是不是所有对象的创建都交给spring来管理?
回答:理论上是的,但是业存在特例:实体对象(entity)是不会交给spring来创建的,它是由持久层框架来创建的
3.spring 5.x与日志框架的整合
原因:spring与日志框架进行整合,日志框架就可以在控制台中,输出spring运行过程中一些重要信息
好处:便于了解spring框架的运行过程,便于程序调试
- 如何整合
默认:
spring1.2.3早期都是Commons-logging。jar
spring5.x整合的是logback、log2j2
spring5.x整合log4j
1.引入log4j.jar
2.引入配置文件loj4j.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.25</version>
</dependency>
引入配置文件
# 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