工厂模式是一种在工程中广泛应用的设计模式,对代码的解耦合起到了很大的作用。在Spring使用开发中,我们可以将Spring理解成封装了我们工程中大量重复代码的一种工具,Spring中最为重要的组件就是IOC,而IOC中非常重要的部分就是应用了工厂模式的代码。而工厂模式依赖于Java的反射机制,所以,我们从反射机制讲起,一步步了解Spring的Bean工厂。
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。
(3)在框架的底层使用非常多的设计模式,算法,还有反射等,我们可以通过反射去创建对象,简单点说,在学习面向对象的所有操作几乎都可以使用反射进行实现,下面来看个最常见的通过反射创建对象。
Class.forName("com.mysql.jdbc.Driver");
//数据库加载驱动可能就是我们学习反射之后,第一个写的连接数据库的工具类,我们还可以通过反射做其他操作newInstance()创建实例
//getClassLoader() 获取类加载器等
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
我们本次创建的是一个完整的通用工厂实例
实体类
package demo;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
Dao层接口
package demo.dao;
import demo.User;
public interface UserDao {
public void login();
public User regeister(User user);
}
Dao层接口实现类
package demo.dao;
import demo.User;
public class UserDaoImpl implements UserDao{
public void login() {
System.out.println("login----UserDaoImpl");
}
public User regeister(User user) {
return user;
}
}
Service接口
package demo.Service;
import demo.User;
public interface UserService {
public void login();
public User regeister(User user);
}
Service接口实现类
package demo.Service;
import demo.User;
import demo.Factory.UserFactory;
import demo.dao.UserDao;
public class UserServiceImpl implements UserService {
private UserDao userDao = (UserDao)UserFactory.getUserServiceImpl("userDao");
/*这里就是通过我们写的工厂,通过反射进行对象的创建,接收的是一个
字符串类型的值,该值就是读取的配置文件中的key
*/
public void login() {
userDao.login();
}
public User regeister(User user) {
return userDao.regeister(user);
}
}
properties配置文件
userService=demo.Service.UserServiceImpl
userDao=demo.dao.UserDaoImpl
#以key=value的形式 可以用等号分割也可以用空格进行分割key value
#这里的两个value都是对应类的绝对路径
BeanFactory工厂 —通用工厂用来通过反射进行对象的创建
package demo.Factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import demo.Service.UserService;
import demo.Service.UserServiceImpl;
public class BeanFactory {
public static Properties env = new Properties();
//这里使用的时静态方法读取的routes.properties配置文件
static {
InputStream inputStream =null;
try {
inputStream = BeanFactory.class.getResourceAsStream("/routes.properties");
env.load(inputStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(inputStream!=null) {
try {
//在finally中关闭输入流
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static Object getUserServiceImpl(String routes) {
Object rel =null;
try{
Class clazz = Class.forName(env.getProperty(routes));
rel = clazz.newInstance();
}catch(Exception e){
e.printStackTrace();
}
return rel;
}
}
所用到的方法
相信第一次看的时候会对这写方法有些疑问,毕竟这些都是在java之初就学习的,顺便复习一下
1. inputStream = BeanFactory.class.getResourceAsStream("/routes.properties");
Object.class.getResourceAsStream()方法
如果写一个类需要动态的获取某个文件的位置,从而能够获取此文件的资源。那么,使用class.getResourceAsStream()方法便可以。
这样就不用每次去修改代码中文件的绝对地址或详细地址了。
2. env.load(inputStream)
load(InputStream)方法就是逐行读取properties配置文件,分隔成两个字符串key和value,将他们放进Properties对象中。
3.env.getProperty(routes)
getProperty(String key)获取配置文件中对应key的value值
**测试类**
package demo.Test;
import demo.User;
import demo.Factory.UserFactory;
import demo.Service.UserService;
import demo.Service.UserServiceImpl;
public class UsetTest {
public static void main(String[] args) {
String routes = "userService"; //配置文件中的key
UserService userService =(UserService)UserFactory.getUserServiceImpl(routes);
userService.login();
User user = new User();
user.setUsername("admin");
user.setPassword("123456");
System.out.println(userService.regeister(user));
}
}
运行结果
其他内容
学习不是即学即用,而是用的时候已经掌握。
Java学习之初疑问
Markdown基本语法
MySQL设置级联操作