对象延迟加载机制

16 篇文章 0 订阅

       在复杂的对象创建时,往往需要创建很多它所依赖的对象,通常这些所依赖的对象创建比较耗时,并且只有少数依赖的对象会被立即使用,其他依赖对象暂时不会使用到,这时候就用该考虑使用延时加载了。

       .NET 中使用Lazy<T>这样的形式来实现延时加载。

1..NET中的Lazy加载

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LazyLoadDemo
{
    internal class LargeObject
    {
        public LargeObject()
        {

        }

        public void Test()
        {
            Console.WriteLine("Test");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var lazyObject = new Lazy<LargeObject>();

            lock (lazyObject)
            {
                Console.WriteLine(lazyObject.IsValueCreated);
                lazyObject.Value.Test();
                Console.WriteLine(lazyObject.IsValueCreated);
                lazyObject.Value.Test();
                Console.WriteLine(lazyObject.IsValueCreated);
            }
            
            Console.ReadKey();
        }
    }
}
输出结果如下:

False
Test
True
Test
True
这时候我们发现,延迟加载有一个是否已加载的标记,如果已经加载了,则第二次直接返回已加载的对象实例。

2.自己实现的延迟加载

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LazyDemo2
{
    internal class MyLazyObject<T> where T : new()
    {
        private T _value;

        private bool _isLoaded;

        public MyLazyObject()
        {
            _isLoaded = false;
        }

        public bool IsLoaded
        {
            get { return _isLoaded; }
        }

        public T Value
        {
            get
            {
                if (!_isLoaded)
                {
                    _value = new T();
                    _isLoaded = true;
                }
                return _value;
            }
        }
    }

    internal class LargeObject
    {
        public LargeObject()
        {

        }

        public void Test()
        {
            Console.WriteLine("Test");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var lazyObject = new MyLazyObject<LargeObject>();

            lock (lazyObject)
            {
                Console.WriteLine(lazyObject.IsLoaded);
                lazyObject.Value.Test();
                Console.WriteLine(lazyObject.IsLoaded);
                lazyObject.Value.Test();
                Console.WriteLine(lazyObject.IsLoaded);
            }
            
            Console.ReadKey();
        }
    }
}
这里我们自己来实现对象的延迟加载,同样我们设定一个是否已经加载的标记。当对象已经被加载之后,我们就不再创建新的对象,而是直接返回实例!这里已经考虑了线程安全的问题,一个线程在使用当前的对象,另一个线程需要等待,保证了对象的唯一性。

3.Java中的延迟加载

1)Spring的延迟加载

Spring 作用就是装载bean,默认都是及时加载的,如果遇到大对象需要延迟加载怎么解决呢?其实Spring使用配置就可以解决延迟加载的问题了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <bean id="employeeBean" class="javabeat.net.spring.ioc.Employee" />
    <bean id="addressBean" class="javabeat.net.spring.ioc.Address"
        lazy-init="true" />
</beans>
该配置中的lazy-init设置为true,Spring 就可以对其进行延迟加载!

注意:Spring配置延迟加载有两种方式,一种是配置在bean的节点上,另外一种是配置在beans节点上,前者只会影响到当前的bean,后者则会影响到所有的bean!

2)Hibernate的延迟加载

下面是hibernate延迟加载配置的实例:

Team.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="edu.dgut.ke.model.Team" table="TEAM" lazy ="true" ><!-- 多对一的延迟加载设置 -->
        <id name="id" type="java.lang.String">
            <column name="ID" length="32" />
            <generator class="uuid.hex" />
        </id>
        <property name="teamname" type="java.lang.String">
            <column name="TEAMNAME" length="32" not-null="true" unique="true" />
        </property>
        <set name="students" inverse="true" cascade="all" lazy="true" > <!-- 一对多的延迟加载设置 -->
            <key>
                <column name="TEAMID" length="32" not-null="true" />
            </key>
            <one-to-many class="edu.dgut.ke.model.Student" />
        </set>
    </class>
</hibernate-mapping>
Certificate.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="edu.dgut.ke.model.Certificate" table="CERTIFICATE" lazy="true" ><!-- 一对一的延迟加载设置 -->

        <id name="id" type="java.lang.String">
            <column name="ID" length="32" />
            <generator class="uuid">

            </generator>
        </id>
        <property name="describe" type="java.lang.String">
            <column name="`DESCRIBE`" length="50" not-null="true" />
        </property>
        <one-to-one name="student"
        class="edu.dgut.ke.model.Student"
         constrained="true" ><!-- 一对一的延迟加载设置 -->

        </one-to-one>
    </class>
</hibernate-mapping>
Student.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="edu.dgut.ke.model.Student" table="STUDENT" lazy="true" >
        <id name="id" type="java.lang.String">
            <column name="ID" length="32" />
            <generator class="uuid.hex" />
        </id>
        <many-to-one name="certificate" 
        class="edu.dgut.ke.model.Certificate"
        unique="true"
        column="cardId"
        cascade="all"
        >
        </many-to-one>
        <many-to-one name="team" class="edu.dgut.ke.model.Team">
            <column name="TEAMID" length="32" not-null="true" />
        </many-to-one>
        <property name="studentname" type="java.lang.String">
            <column name="STUDENTNAME" length="16" not-null="true" unique="true" />
        </property>
    </class>
</hibernate-mapping>
注意:对one-to-one 关系进行延迟加载和其他关系相比稍微有些不同。many-to-one 的延迟加载是在配置文件的class 标签
上设置 lazy="true" ,one-to-many 和 many-to-many 的延迟加载是在 set 标签中设置lazy="true"。而one-to-one 不只要在 classs 
标签设置 lazy="true",而且要在one-to-one 标签中设置constrained="true" 。
如果不设置constrained="true",则一对一查询使用默认的预先抓取策略(fetch="join")。
4.总结

延迟加载的机制是大对象的管理的一部分,关于大对象管理还有大对象的回收机制等等,之前也发表过一篇关于大对象造成的内存碎片的问题的博客。在构建复杂系统的时候如何确保对象正确构建很重要,同时如何确保对象按需加载也非常重要,尤其是对于性能优化方面。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值