创建bean对象的工厂
bean在计算机英语中,有可重用组件的含义
可重用:可反复使用。组件:组成部分,比如service可以被servlet反复使用,dao被service使用。service可以看成是可重用的组成部分。
javabean>=实体类,用Java语言编写的可重用组件
bean对象的工厂它就是创建service和dao对象的
如何创建:
第一个需要一个配置文件来配置我们的service和dao
配置的内容:全限定类名,唯一标识(key-value)(用于取到这个类)
第二个通过读取配置文件中配置的内容,反射创建对象
我的配置文件可以时xml也可以时properties,properties较为简单
bean.properties
accountService=com.yujie.service.Impl.AccountServiceImpl
accountDao=com.yujie.dao.dao.Impl.AccountDaoImpl
public class BeanFactory {
//定义一个properties对象
private static Properties props;
//使用静态代码块为properties对象赋值
static{
try {
//实例化对象
props = new Properties(); //降低,而不是消除
//获取properties文件的流对象,类加载器是动态获取文件的绝对路径
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); //获取配置文件
props.load(in); //读取流
}catch (Exception e){
throw new ExceptionInInitializerError("初始化properties失败")
}
}
//这里不能写死了某个类名
//根据bean的名称获取bean对象,通过读取配置文件的方式完成反射
public static Object getBean(String beanName){
Object bean=null;
try {
String beanPath = props.getProperty(beanName); //通过beanname来得到bean的路径
bean = Class.forName(beanPath).newInstance(); //通过反射机制来获取对象
}catch(Exception e){
e.printStackTrace();
}
return bean;
}
}
能不能解耦呢?下面改装一下,实现解耦
public class Client {
public static void main(String[] args) {
// IAccountService as=new AccountServiceImpl();
IAccountService as=(IAccountService)BeanFactory.getBean("accountService");
as.saveAccount();
}
}
public class AccountServiceImpl implements IAccountService {
// private IAccountDao accountDao=new AccountDaoImpl();
private IAccountDao accountDao=(IAccountDao) BeanFactory.getBean("accountDao");
public void saveAccount() {
accountDao.saveAccount();
}
}
这个就是工厂模式解耦,我们把accountDao给删掉,编译时没问题,运行时才报错
这就是工厂模式解耦
但是这个代码仍然有问题,
for(int i=0;i<5;i++){
IAccountService as=(IAccountService)BeanFactory.getBean("accountService");
System.out.println(as);
}
打印出来了5个对象,这时候对象是多例的,单例对象是说从始至终只有一个对象实例。他们有什么区别呢,
在serviceImpl中,i是一个类的成员,方法操作类成员的属性
private int i=1;
public void saveAccount() {
accountDao.saveAccount();
System.out.println(i);
i++;
}
这时候i一直是1,不管有多少个service访问的时候,都是1。
如果是单例的话,此时每个编码都应该相同,比如5个都是com.yujie.service.Impl.AccountServiceImpl@74a14482
只被创建一次,从而类中的成员也就只会初始化一次。所以多个线程访问,多个对象访问时,由于对象的实例只有一个,类成员在方法能够进行改变的时候,单例就出现了。
多例对象对象被创建多次,其执行效率没有单例对象高
单例对象有线程问题,但是在我们service和dao中,没有类的方法对其类的属性进行调整,而是会把属性定义到方法中去,每次方法都会对他重新初始化,也能保证每次得到的都是1。
所以我们需要每次都是同一个对象,由于beanfactory创建对象的时候调用的时newInstance,每次都会调用默认构造函数创建对象。调整的前提是,我们的newInstance只能一次,如果创建了不存起来,Java的垃圾回收机制就会长时间不用时回收。所以在对象创建起来之后就要存起来
我们需要存储这些对象的,我们称之为容器
定义一个Map,用于存放我们要创建的对象,我们把它称之为容器
public class BeanFactory {
//定义一个properties对象
private static Properties props;
//定义一个Map,用于存放我们要创建的对象,我们把它称之为容器
private static Map<String,Object> beans;
//使用静态代码块为properties对象赋值,静态代码块只在类加载的时候执行一次
static{
try {
//实例化对象
props = new Properties(); //降低,而不是消除
//获取properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"); //获取配置文件
props.load(in); //读取流
//用hashMap实例化容器
beans=new HashMap<String, Object>();
//取出配置文件中所有的key
Enumeration keys=props.keys();
//遍历枚举
while(keys.hasMoreElements()){
//取出每个key
String key=keys.nextElement().toString();
//根据key获取value
String beanPath=props.getProperty(key);
//反射创建对象
Object value=Class.forName(beanPath).newInstance();
//把key和value存入容器中
beans.put(key,value);
}
}catch (Exception e){
throw new ExceptionInInitializerError("初始化properties失败");
}
}
//根据bean的名称获取对象,这个对象时单例的
public static Object getBean(String beanName){
return beans.get(beanName);
}
}
此时输出结果如上,当多个人在使用它访问时,此时就时单线程。第一个人再修改,后面的也跟着看到修改的结果,但是持久层和业务层不要定义可修改的类成员。