javaEE学习笔记9-21

优化的工厂模式

不加修改时,循环地调用工厂模式,将产生多个对象。这组对象将单独,独立地调用自己的方法。

工厂利用反射创建对象的语句:

bean=Class.forName(beanPath).newInstance();

由于使用了newInstance(),每次调用都必然调用默认构造函数,创建新对象。

使用单例对象,避免创建大量对象,可以提高程序效率。
解决方案:只使用一次newInstance方法,用容器(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);
            //实例化容器
            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失败!");
        }
    }

由于静态代码块只在类加载时执行一次,故此时只会创建一个对象。这时,重定义get方法,直接根据传入的bean名返回对象即可。

优化后,工厂模式的整个流程,自顶向下地描述为:

  1. main()方法调用factory.getBean(beanName)尝试获取组件。
  2. 加载工厂类,静态地创建容器。
  3. 使用类加载器获取配置文件流,替代绝对路径与相对路径。
  4. 根据配置文件(properties),填充容器。
  5. get方法根据传入的beanName,将容器中存储的对应对象传出。

在具体开发中,几乎每个类,都定义了接口,我不确定这是否必要,程序需要多层抽象,业务逻辑和实现逻辑完全分层。通过在高层类中实例化低层类的私有对象来实现。

控制反转(IOC)

使用New创建对象,相当于程序主动寻求资源(来创建对象);使用工厂模式,结构变化为:程序-寻求资源->工厂-控制资源->资源。这样就降低了依赖。

控制反转:需要创建对象的类,将创建对象的权利交给工厂。

Spring的IOC

Spring提供了上述部分 工厂 的功能。

这就是为什么我们需要一个额外的配置文件的原因:在项目pom.xml之外,需要新创建一个xml文件(在resoures文件夹下),它替代了此前properties配置文件的功能。
在这个xml文件中,我们指定spring负责工厂的功能,并指定Id和反射对象。

通过查找spring文档获取用于指定spring负责工厂的xml代码。
通过类似:

<bean id="" class=""></bean>

来添加反射相关配置。

那么类似上面的思路,先获取spring的核心容器,再根据id获取对象:

public static void main(String[] args){
	//获取核心容器对象,前面是接口     这是实现类
	ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
	//或者使用,不推荐
	//ApplicationContext ac = new FileSystemXmlApplicationContext("绝对路径");
	
	//根据id获取bean对象
	IAccountService as = (IAccountService)ac.getBean("accountService");
	//和上面的工作一致,第二个参数完成类型转换
	IAccountDao adao = ac.getBean("accountDao", IAccountDao.class)
}

Spring管理bean对象

创建Bean对象

  1. 在配置中使用Bean标签,只配有id和class属性,没有其他属性和标签,调用默认构造函数创建对象,如果没有显式声明(java需要显式声明)则创建失败。
  2. 使用工厂/某个类中的方法创建对象,并存入Spring容器。
<bean id="instanceFactory" class="com.test.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

第二个标签项指向了第一个,并告知spring通过其中的getAccountService方法创建对象。
    3. 使用工厂/某个类中的静态方法来创建对象,并存入Spring容器。

<bean id="accountService" class="com.test.factory.StaticFactory" factory-method="getAccountService"></bean>

类似第二种方法,但是通过factory-method指定了调用访问到的类的方法。

bean的作用范围

通过指定bean 标签的scope属性,确定bean的作用范围。

<bean id="accountService" class="com.test.factory.StaticFactory" scope="singleton"></bean>

取值:
singleton: 单例的(默认值)
prototype: 多例的
request
session
global-session

bean的生命周期

单例对象:和容器相同,加载类时就会创建(立即创建)
多例对象:使用对象时,spring对象才会创建它。(延迟创建)长时间不使用时,由java执行回收。

依赖注入

使用构造函数注入

<bean id="accounetService" class="com.test.service.impl.AccountServiceImpl">
<!-- name是参数名 -->
	<constructor-arg name="name1" value="test"></constructor-arg>
	<constructor-arg name="age" value="18"></constructor-arg>
	<constructor-arg name="data" ref="now"></constructor-arg>
</bean>
<bean id="now" class="java.util.Date"></bean>

所有的配置都被存入容器之中,通过id来访问。
value指向基本类型和String类型
ref指向其他bean类型。
两者结合起来,保证能向构造函数传递任意类型的数据。(对于其他类型,也是由基本类型产生的)

set方法注入(更常用)

在类中定义各个参数的set方法,之后在xml中添加:

<bean id="accounetService" class="com.test.service.impl.AccountServiceImpl">
<!-- name是参数名 -->
	<property name="name1" value="test"></property>
	<property name="age" value="18"></property>
	<property name="data" ref="now"></property>
</bean>
<bean id="now" class="java.util.Date"></bean>

由于set方法,在构造函数中,可以任意地指定参数,不会报警,更灵活了,这是优势,也是劣势(相较于构造函数注入来说)

集合类型的注入:
在property标签内,嵌入类似
<array><value>AAA</value>...</array>
其中,array可以替换为list set等集合类型。

也可以给map结构集合注入:
使用 map props 标签


听课笔记,仅供参考,如果您发现错误,欢迎在评论区指出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值