三级缓存原理

//定义一个加载图片的类

public class MyFresco {
    private static MyMemocyCache myMemocyCache;
    private static MyDiskCache myDiskCache;
    private static MyFresco myFresco;
    private static Context mContext;
    public static MyFresco init(Context context){
        myMemocyCache=new MyMemocyCache();
        myDiskCache=new MyDiskCache();
        myFresco=new MyFresco();
        mContext=context;
        return myFresco;
    }
    //加载图片的方法
    public Bitmap loadPic(String url){
        //检查内存里有没有
        Bitmap picFromMemory = myMemocyCache.getPicFromMemory(url);
        if (picFromMemory==null){
            //去磁盘里获取
            Bitmap picFromDisk = myDiskCache.getPicFromDisk(url);
            if (picFromDisk==null){
            //去网络获取图片
                Bitmap picFromNet = getPicFromNet(url);
                if (picFromNet==null){
                    //网络图片没有就返回一个默认图片
                 Bitmap bitmap= BitmapFactory.decodeResource(mContext.getResources(),R.mipmap.ic_launcher);
               return bitmap;
                }else {
                    return picFromNet;
                }
            }else {
                return picFromDisk;
            }
        }else {
            return picFromMemory;
        }

    }
    //从网络中获取图片
    public Bitmap getPicFromNet(String url){
        //使用HttpUrlConnction
        URL u = null;
        try {
            u = new URL(url);
           HttpURLConnection connection = (HttpURLConnection) u.openConnection();
           connection.setConnectTimeout(5000);
           if (connection.getResponseCode()==200){
               InputStream inputStream = connection.getInputStream();//获取输入流相当于Bitmap
               Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
               return bitmap;
           }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
//内存缓存类

public class MyMemocyCache {
    //内存大小的1/8
   private long size=Environment.getDataDirectory().getUsableSpace();
  private LruCache<String,Bitmap> lruCache=new LruCache<>((int) (size/8));
    //取出图片
public Bitmap getPicFromMemory(String url){
    Bitmap bitmap = lruCache.get(url);
    return bitmap;
}
    //向内存中保存图片
    public void setPicToMemocy(String url,Bitmap bitmap){
       lruCache.put(url,bitmap);
    }
}

//sdcard缓存类

public class MyDiskCache {
    private String path= Environment.getExternalStorageDirectory().getAbsolutePath();
    //保存图片
    public void setPicToDisk(String url){
        File file = new File(path, url);
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
        try {
            bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));//将图片压缩到sdcard
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //取出图片
    public Bitmap getPicFromDisk(String url){
        File file = new File(path, url);
        if (file.exists()){
            Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            return bitmap;
        }

        return null;
    }
}

//主activity调用

public class MainActivity extends AppCompatActivity {
private String pic="http://www.taopic.com/uploads/allimg/140320/235013-14032020515270.jpg";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button start = findViewById(R.id.start);
        final ImageView image = findViewById(R.id.image);
        final MyFresco init = MyFresco.init(this);
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(){
                    @Override
                    public void run() {
                        super.run();
                        final Bitmap bitmap = init.getPicFromNet(pic);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                image.setImageBitmap(bitmap);
                            }
                        });

                    }
                }.start();
            }
        });
    }

布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.huancun.MainActivity">

   <Button
       android:text="加载"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:id="@+id/start"/>
<ImageView
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:id="@+id/image"/>
</LinearLayout>

<think>我们正在讨论Spring框架中的三级缓存机制,特别是它如何解决循环依赖问题。根据引用内容,三级缓存实际上是三个Map,分别存储不同状态的bean实例。下面我将逐步解释三级缓存的工作原理:1.**三级缓存的组成**(引用[4]):-**一级缓存(singletonObjects)**:存储已经完全初始化好的单例bean(beanName→bean实例)。这是最终可用的bean。-**二级缓存(earlySingletonObjects)**:存储早期暴露的bean实例(beanName→bean实例)。这些bean已经实例化但尚未完成初始化(属性填充等)。-**三级缓存(singletonFactories)**:存储单例工厂对象(beanName→ObjectFactory)。这个工厂对象可以生成bean的早期引用(通过代理或原始对象)。2.**解决循环依赖的核心流程**(引用[1][3][4]):-假设有两个bean:A和B,它们相互依赖(A依赖B,B依赖A)。-当创建A时:-首先,通过构造器实例化A(此时A还未初始化)。-然后,将A的ObjectFactory放入三级缓存(`singletonFactories`)。-接着,开始为A注入属性,此时发现需要B。-转而去创建B:-实例化B后,将B的ObjectFactory放入三级缓存。-为B注入属性时,发现需要A。-此时,从三级缓存中查找A:-通过A的ObjectFactory获取A的早期引用(可能是原始对象或代理对象),并将这个早期引用放入二级缓存(`earlySingletonObjects`),同时从三级缓存移除A的ObjectFactory。-将A的早期引用注入到B中。-B完成初始化,放入一级缓存。-回到A的创建流程,将B(已从一级缓存获取)注入A,然后A完成初始化,放入一级缓存。3.**为什么需要三级缓存?**(引用[1][4]):-二级缓存(earlySingletonObjects)存储的是尚未初始化的bean实例,用于解决循环依赖。-三级缓存(singletonFactories)存储的是ObjectFactory,它的作用是在需要循环依赖时,能够生成早期引用。这个工厂对象可以处理AOP代理的情况:如果bean需要代理,则ObjectFactory会返回代理对象;否则返回原始对象。这样保证了注入到其他bean中的是最终需要的对象(可能是代理对象)。4.**构造器注入循环依赖为何不支持?**(引用[3]):-在构造器注入中,bean在实例化时就需要依赖项。此时bean还未实例化,无法将其ObjectFactory放入三级缓存,因此无法解决循环依赖。5.**三级缓存的设计意义**(引用[2]):-通过三级缓存,Spring能够减少重复创建bean的开销,并有效解决Setter/Field注入的循环依赖问题,提升性能和可维护性。总结:Spring的三级缓存机制通过三个Map协作,在bean创建过程中适时暴露早期引用,从而解决循环依赖问题。其中,三级缓存(singletonFactories)是关键,它提供了生成bean早期引用的能力,并处理了AOP代理的情况。</think>### Spring框架三级缓存实现原理详解 Spring三级缓存机制是解决单例Bean循环依赖的核心设计,其核心在于三个Map的协同工作(引用[4]): #### 三级缓存结构 ```java // 一级缓存:存储完全初始化的Bean private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 二级缓存:存储提前暴露的Bean(未完成属性注入) private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 三级缓存:存储Bean工厂对象 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); ``` #### 工作流程(以A→B→A循环依赖为例) 1. **创建Bean A** - 实例化A(调用构造器) - 将A的`ObjectFactory`存入三级缓存(引用[1]) ```java addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); ``` 2. **属性注入A** - 发现A依赖B → 触发B的创建 3. **创建Bean B** - 实例化B - 将B的`ObjectFactory`存入三级缓存 4. **属性注入B** - 发现B依赖A → 从缓存查找A: ```mermaid graph LR 查找一级缓存 --> 失败 查找二级缓存 --> 失败 查找三级缓存 --> 发现A的ObjectFactory ``` - 通过`ObjectFactory.getObject()`获取A的**早期引用**(未初始化的半成品) - 将A从三级缓存升级到二级缓存(引用[4]) 5. **完成B的初始化** - B注入A的早期引用后完成初始化 - B存入一级缓存 6. **完成A的初始化** - A注入完整的B实例 - A从二级缓存移除,存入一级缓存 #### 关键设计点 1. **缓存升级机制**(引用[3]): ``` 三级缓存 → 二级缓存 → 一级缓存 ``` - 首次暴露:三级缓存(工厂对象) - 被依赖时:升级到二级缓存(原始对象/代理对象) - 初始化完成:存入一级缓存 2. **ObjectFactory的作用**(引用[1][4]): - 延迟创建代理:当存在AOP时,通过`getEarlyBeanReference()`生成代理对象 - 避免重复创建:确保循环依赖中多个Bean引用同一个代理实例 3. **适用场景限制**(引用[3]): ``` +----------------+------------------+-----------------------+ | 作用域类型 | 构造器注入循环 | Setter/Field注入循环 | +----------------+------------------+-----------------------+ | Singleton | 不支持 | 支持 | | Prototype | 不支持 | 不支持 | +----------------+------------------+-----------------------+ ``` #### 设计意义 1. **解耦创建过程**:将实例化与初始化分离,允许暴露未完成初始化的对象 2. **代理兼容**:通过ObjectFactory解决AOP代理对象的循环依赖问题 3. **性能优化**:避免重复创建对象(引用[2]) > 三级缓存本质是空间换时间的解决方案,通过缓存不同状态的Bean实例,在保证单例唯一性的前提下突破循环依赖的限制[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值