Когда объект объекта-прототипа собирает мусор, когда мы используем прокси-режим для Scope Protype в Spring Boot - PullRequest
4 голосов
/ 12 октября 2019

когда компонент-прототип будет собирать мусор, если мы используем прокси-режим для прототипа области для класса в загрузке Spring, будет ли он обрабатываться Spring?

, когда объект MyClassB будет собирать мусор в следующем примереили это приводит к утечке памяти?

 @Service
    public class MyClassA {

        @Autowired
        private MyClassB myClassB;

        public String findMydata(String input) {

            String myData = myClassB.getSomeData(input);    
            return myData;
        }
    }

Ниже приведен класс с прототипом области видимости, который используется вышеуказанным классом

@Service
@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE,
       proxyMode=ScopedProxyMode.TARGET_CLASS)
public class MyClassB {

        MyPojoClassA mypojoA = null;
        MyPojoClassB mypojoB = null;     

    @Autowired
    private MyClassC myClassC;

    @Autowired
    private myClassD myClassD;

    public String getSomeData(String input) {
        String SomeData = "";

            myMethodA(input);

            // makes call to external service for data  
        SomeData = myClassC.getSomeData(mypojoA.getSomething());
        myMethodB(mypojoA.getSomeOthervalue());

        if(SomeData.isBlank()){
                // retrieve the data from database.
            SomeData = myClassD.getSomeData(mypojoB.getSomething());
        }
        return SomeData;
    }

        private void myMethodA(String input){
           // process and set values in mypojoA
        }
        private void myMethodB(String input){
           // process and set values in mypojoB
        }
}

Использование и присвоение значений различным полям myPojoAи myPojoB выполняется несколько раз, вызывая разные закрытые методы внутри метода getSomeData. здесь, в примере кода, я не сделал эти призывы к простоте, но должен показать, что используются две ссылочные переменные уровня экземпляра двух классов.

Ответы [ 2 ]

1 голос
/ 19 октября 2019

Если на объект не ссылаются / не используют другие объекты, он имеет право на GC. ( Источник , см. Раздел Описание сбора мусора) .

В вашем примере, хотя вы вводите прототип MyClassB в одноэлементный MyClassA, MyClassAвсегда будет обращаться к одному и тому же экземпляру MyClassB, главным образом потому, что внедрение MyClassB в MyClassA произойдет только один раз при создании экземпляра MyClassA. Это поведение хорошо объяснено в документах следующим образом:

Когда вы используете компоненты с одинарной областью действия с зависимостями от компонентов-прототипов, имейте в виду, что зависимости разрешаются во время создания экземпляра. Таким образом, если вы вводите зависимый bean-объект с прототипом в bean-объект синглтона, создается новый bean-объект-прототип и затем внедряется зависимость в синглтон-компонент. Экземпляр прототипа является единственным экземпляром, который когда-либо предоставляется компоненту с одной областью действия.

Однако предположим, что вы хотите, чтобы компонент с единичной областью повторно получал новый экземпляр компонента с прототипом во время выполнения. Вы не можете внедрить зависимый bean-объект с прототипом в ваш одноэлементный bean-компонент, потому что это внедрение происходит только один раз, когда контейнер Spring создает экземпляр одноэлементного bean-компонента и разрешает и внедряет его зависимости.

As MyClassAявляется единственным, он всегда существует во время выполнения приложения. Это означает, что его зависимости (то есть MyClassB) всегда будут использоваться этим экземпляром MyClassA, и они никогда не будут иметь права на GC.

Если вы хотите создавать новый экземпляр MyClassB всякий раз, когда MyClassAДоступ MyClassB, вы можете использовать один из следующих методов описания здесь . Просто убедитесь, что новый экземпляр MyClassB никогда не будет назначен полям какого-либо одноэлементного компонента, тогда он будет иметь право на GC при выходе из этого метода. Что-то вроде:

@Service
public class MyClassA {

        @Autowired
        private Provider<MyClassB> myClassB;

        public String findMydata(String input) {
            MyClassB classB = myClassB.get(); 
            String myData = classB.getSomeData(input);    
            return myData;
        }
}

Я использую технику 5, описанную в this .

0 голосов
/ 18 октября 2019

Согласно документации Spring ваш клиентский код отвечает за удаление бинов. Я предполагаю, что это похоже на InputStream классы реализации, которые должны быть закрыты вручную (путем вызова close() или с помощью try-with-resources). Вызванный метод destroy может быть настроен следующим образом:

@Bean(destroyMethod = "closeMyBean")
public MyBean myBean(){}

Мне неясно, удалит ли это немедленно компонент или сделает его подходящим для сборщика мусора Java, но поскольку компоненты Spring обычно не управляютсяJVM подозревает, что bean-компонент исчезнет, ​​когда завершится выполнение метода destroy.

Обратите внимание на следующее в документации:

Код клиента должен очистить прототип-областьобъекты и выпустить дорогие ресурсы, которые хранятся в прототипахЧтобы заставить контейнер Spring высвобождать ресурсы, содержащиеся в bean-компонентах с прототипом, попробуйте использовать собственный постпроцессор bean-компонента, который содержит ссылку на bean-компоненты, которые необходимо очистить.

, в котором указано, что вы должнывысвободить любые ресурсы, содержащиеся в компоненте, как часть метода уничтожения или перед этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...