Страницы

Поиск по вопросам

Показаны сообщения с ярлыком pool. Показать все сообщения
Показаны сообщения с ярлыком pool. Показать все сообщения

воскресенье, 9 февраля 2020 г.

Пул констант в Java

#java #переменные #const #константа #pool


Не раз слышал о так называемом пуле констант в языке программирования Java. Знаю
о пуле объектов типа String, пуле для типов Byte, Short, Character, Integer, Long и
даже Boolean. Также знаю, что мы сами можем определять размер пула типа Integer, если
запускать приложение с параметром -Djava.lang.Integer.IntegerCache.high=XX, где XX
может колебаться в диапазоне от 127 до (Integer.MAX_VALUE - 129). Весь этот пул представляет
собой массив, каждое значение которого является элементом расположенным в порядке числового
возрастания и мы можем напрямую обратиться к нему по индексу за константное время O(1).
Я прекрасно понимаю, где хранится этот массив. У каждого целочисленного обёрточного
типа есть свой вложенный класс такого типа: 

private static class WrappingСlassNameCache {...}  


Где вместо WrappingСlassNameCache, мы подставляем конкретное имя класса, к примеру,
IntegerCache. 
Внутри это выглядит так: 

private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            try {
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);

        // range [-128, 127] must be interned (JLS7 5.1.7)
        assert IntegerCache.high >= 127;
    }


Ну Бог с ним, тут ничего мудрёного нет! А что же такое пул констант? Что он из себя
представляет? И вообще где хранятся все константы в Java? Если мы говорим о локальных
финализированных переменных, то они хранятся в стековой памяти. Если мы имеем дело
со static final полями, то эти поля хранятся в MetaSpace (раньше в PermGen), если мы
говорим о реализации JVM HotSpot. Так о каком вообще пуле может идти речь? Как всё
это реализовано? Описано в каком-то классе, который поставляется вместе со стандартным
API от Oracle (раньше Sun Microsystems) или же это нужно заглядывать в реализацию конкретной
JVM и читать JVMS? Подскажите, пожалуйста, надоело, что в которой раз сталкиваюсь с
этим понятием и никак не могу понять о чём идёт речь. Всем огромное спасибо за помощь! :)
    


Ответы

Ответ 1



У каждого класса свой пул констант. Чтобы понять для чего он нужен, разберём простой пример class Example { public void hello() { System.out.println("Hello"); } } Скомпилируем $ javac Example.java И заглянем внутрь $ javap -c -v Example.class public class Example minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #20 // Example #6 = Class #21 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 hello #12 = Utf8 SourceFile #13 = Utf8 Example.java #14 = NameAndType #7:#8 // "":()V #15 = Class #22 // java/lang/System #16 = NameAndType #23:#24 // out:Ljava/io/PrintStream; #17 = Utf8 Hello #18 = Class #25 // java/io/PrintStream #19 = NameAndType #26:#27 // println:(Ljava/lang/String;)V #20 = Utf8 Example #21 = Utf8 java/lang/Object #22 = Utf8 java/lang/System #23 = Utf8 out #24 = Utf8 Ljava/io/PrintStream; #25 = Utf8 java/io/PrintStream #26 = Utf8 println #27 = Utf8 (Ljava/lang/String;)V { public Example(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0 public void hello(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 3: 0 line 4: 8 } Первое, что представляет интерес - это байткоды метода hello: 0: getstatic #2 3: ldc #3 5: invokevirtual #4 Цифры до двоеточия обозначают байт, с которого начинается байткод и его параметры. По шагу видно, что каждая операция - это два байта, один байт на код операции и один байт на параметр. Байткоды могут принимать только параметры фиксированного размера - integer, long, short, byte, character, float, double, reference. Чтобы передать в метод println строку "Hello", надо загрузить в стек ссылку на строку "Hello", а саму строку где-то сохранить. Вот это где-то как раз и есть пул констант. А символы #3 после байткода ldc - ссылка на 3-й элемент в пуле констант. Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V Как можно увидеть из этого кусочка пула, его элементы сами часто ссылаются в пул. В частности наша строка под номером 3 ссылается на массив символов под номером 17. Если говорить о расположении пула констант в памяти JVM, то это один из участков MetaSpace.

пятница, 27 декабря 2019 г.

Инициализация одного пула соединений на разные сервлеты Tomcat

#java #spring #servlet #c3p0 #pool


Есть веб-приложение, в котором в файле web.xml определены два сервлета. 
Есть пул соединений c3p0, который, как я понимаю, должен инициализироваться один раз. 

НО! Если обратиться к одному сервлету, а потом к другому, то пул будет инициализирован
дважды и на каждый сервлет окажется свой пул.

Как это исправить, чтобы пул был общим? 

Конфигурация application-context.xml :




    
    



Конфигурация сервлета 1: 




    




Конфигурация сервлета 2:




    
    



Описание бинов для application-context: 

package ru.rusal.mishka.core;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.eclipse.persistence.jpa.PersistenceProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import javax.persistence.EntityManagerFactory;
import javax.persistence.ValidationMode;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
import java.util.Properties;

@Configuration

public class ContextConfiguration {

    @Bean
    public DataSource dataSource(
            @Qualifier("systemConfiguration") SystemConfiguration systemConfiguration
    ) throws PropertyVetoException {
        Properties props = new Properties();
        props.setProperty("user", systemConfiguration.getDBConfig().getUser());
        props.setProperty("password", systemConfiguration.getDBConfig().getPassword());

        final ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass("oracle.jdbc.OracleDriver");
        dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:DB");
        dataSource.setInitialPoolSize(5);
        dataSource.setMaxPoolSize(20);
        dataSource.setProperties(props);

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            @Qualifier("dataSource") DataSource ds
    ) {
        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setPersistenceUnitName("MilliService");
        factoryBean.setDataSource(ds);
        factoryBean.setPersistenceProviderClass(PersistenceProvider.class);
        factoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
        factoryBean.setValidationMode(ValidationMode.NONE);
        factoryBean.setPackagesToScan("ru.milli.app.persistence");
        factoryBean.getJpaPropertyMap().put("eclipselink.weaving", Boolean.FALSE.toString());
        factoryBean.getJpaPropertyMap().put("eclipselink.allow-zero-id", Boolean.TRUE.toString());

        return factoryBean;
    }

    @Bean
    public JpaTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory factory
    ) throws PropertyVetoException {
        JpaTransactionManager manager = new JpaTransactionManager();
        manager.setEntityManagerFactory(factory);
        return manager;
    }
}


Для сервлетов там обычные rest-сервисы на аннотациях @RestController.

Конфиг web.xml: 




    
    mishka

    
        ru.milli.CleanupContextListener
    

    
        webportal
        org.springframework.web.servlet.DispatcherServlet
    

    
        rest
        org.springframework.web.servlet.DispatcherServlet
    

    
        rest
        /rest/*
    

    
        webportal
        *.html
    

    
        webportal
        /image.jpeg
    

    
        500
        /WEB-INF/jsp/error.jsp
    

    
        404
        /error.html
    

    
        /WEB-INF/jsp/start.jsp
    

    
        
            http://www.springframework.org/tags
            /WEB-INF/tld/spring.tld
        
        
            http://www.springframework.org/tags/form
            /WEB-INF/tld/spring-form.tld
        
    



    


Ответы

Ответ 1



Проблема в том, что вы создаёте 2 DispatcherServlet, и в оба включаете application-context.xml. Согласно документации, A web application can define any number of DispatcherServlets. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc. У каждого DispatcherServlet будет свой контекст Spring, а значит, бины для каждого будут создаваться по отдельности. Тег объединяет текущий конфиг с содержимым импортируемого конфига. Получается, в конфиге каждого сервлета будет объявлен свой пул соединений, и при запуске приложения он создастся два раза. Решить это можно, создав root контекст с бинами, необходимыми всем дочерним контекстам. Делается это при помощи добавления ContextLoaderListener в web.xml: org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:/path/to/application-context.xml Все бины, определённые в root контексте, будут видны в дочерних (web application) контекстах. При этом дочерний контекст может переопределить бин из родительского контекста (объявив свой бин с таким же id), поэтому включать application-context.xml в конфиг каждого сервлета при такой конфигурации не нужно.

понедельник, 15 апреля 2019 г.

Пул констант в Java

Не раз слышал о так называемом пуле констант в языке программирования Java. Знаю о пуле объектов типа String, пуле для типов Byte, Short, Character, Integer, Long и даже Boolean. Также знаю, что мы сами можем определять размер пула типа Integer, если запускать приложение с параметром -Djava.lang.Integer.IntegerCache.high=XX, где XX может колебаться в диапазоне от 127 до (Integer.MAX_VALUE - 129). Весь этот пул представляет собой массив, каждое значение которого является элементом расположенным в порядке числового возрастания и мы можем напрямую обратиться к нему по индексу за константное время O(1). Я прекрасно понимаю, где хранится этот массив. У каждого целочисленного обёрточного типа есть свой вложенный класс такого типа:
private static class WrappingСlassNameCache {...}
Где вместо WrappingСlassNameCache, мы подставляем конкретное имя класса, к примеру, IntegerCache. Внутри это выглядит так:
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[];
static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h;
cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; }
Ну Бог с ним, тут ничего мудрёного нет! А что же такое пул констант? Что он из себя представляет? И вообще где хранятся все константы в Java? Если мы говорим о локальных финализированных переменных, то они хранятся в стековой памяти. Если мы имеем дело со static final полями, то эти поля хранятся в MetaSpace (раньше в PermGen), если мы говорим о реализации JVM HotSpot. Так о каком вообще пуле может идти речь? Как всё это реализовано? Описано в каком-то классе, который поставляется вместе со стандартным API от Oracle (раньше Sun Microsystems) или же это нужно заглядывать в реализацию конкретной JVM и читать JVMS? Подскажите, пожалуйста, надоело, что в которой раз сталкиваюсь с этим понятием и никак не могу понять о чём идёт речь. Всем огромное спасибо за помощь! :)


Ответ

У каждого класса свой пул констант. Чтобы понять для чего он нужен, разберём простой пример
class Example { public void hello() { System.out.println("Hello"); } }
Скомпилируем
$ javac Example.java
И заглянем внутрь
$ javap -c -v Example.class
public class Example minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #20 // Example #6 = Class #21 // java/lang/Object #7 = Utf8 #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 hello #12 = Utf8 SourceFile #13 = Utf8 Example.java #14 = NameAndType #7:#8 // "":()V #15 = Class #22 // java/lang/System #16 = NameAndType #23:#24 // out:Ljava/io/PrintStream; #17 = Utf8 Hello #18 = Class #25 // java/io/PrintStream #19 = NameAndType #26:#27 // println:(Ljava/lang/String;)V #20 = Utf8 Example #21 = Utf8 java/lang/Object #22 = Utf8 java/lang/System #23 = Utf8 out #24 = Utf8 Ljava/io/PrintStream; #25 = Utf8 java/io/PrintStream #26 = Utf8 println #27 = Utf8 (Ljava/lang/String;)V { public Example(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 1: 0
public void hello(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 3: 0 line 4: 8 }
Первое, что представляет интерес - это байткоды метода hello
0: getstatic #2 3: ldc #3 5: invokevirtual #4
Цифры до двоеточия обозначают байт, с которого начинается байткод и его параметры. По шагу видно, что каждая операция - это два байта, один байт на код операции и один байт на параметр. Байткоды могут принимать только параметры фиксированного размера - integer, long, short, byte, character, float, double, reference. Чтобы передать в метод println строку "Hello", надо загрузить в стек ссылку на строку "Hello", а саму строку где-то сохранить. Вот это где-то как раз и есть пул констант. А символы #3 после байткода ldc - ссылка на 3-й элемент в пуле констант.
Constant pool: #1 = Methodref #6.#14 // java/lang/Object."":()V #2 = Fieldref #15.#16 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #17 // Hello #4 = Methodref #18.#19 // java/io/PrintStream.println:(Ljava/lang/String;)V
Как можно увидеть из этого кусочка пула, его элементы сами часто ссылаются в пул. В частности наша строка под номером 3 ссылается на массив символов под номером 17.
Если говорить о расположении пула констант в памяти JVM, то это один из участков MetaSpace.

понедельник, 3 декабря 2018 г.

Инициализация одного пула соединений на разные сервлеты Tomcat

Есть веб-приложение, в котором в файле web.xml определены два сервлета. Есть пул соединений c3p0, который, как я понимаю, должен инициализироваться один раз.
НО! Если обратиться к одному сервлету, а потом к другому, то пул будет инициализирован дважды и на каждый сервлет окажется свой пул.
Как это исправить, чтобы пул был общим?
Конфигурация application-context.xml :


Конфигурация сервлета 1:



Конфигурация сервлета 2:


Описание бинов для application-context:
package ru.rusal.mishka.core;
import com.mchange.v2.c3p0.ComboPooledDataSource; import org.eclipse.persistence.jpa.PersistenceProvider; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory; import javax.persistence.ValidationMode; import javax.sql.DataSource; import java.beans.PropertyVetoException; import java.util.Properties;
@Configuration
public class ContextConfiguration {
@Bean public DataSource dataSource( @Qualifier("systemConfiguration") SystemConfiguration systemConfiguration ) throws PropertyVetoException { Properties props = new Properties(); props.setProperty("user", systemConfiguration.getDBConfig().getUser()); props.setProperty("password", systemConfiguration.getDBConfig().getPassword());
final ComboPooledDataSource dataSource = new ComboPooledDataSource(); dataSource.setDriverClass("oracle.jdbc.OracleDriver"); dataSource.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:DB"); dataSource.setInitialPoolSize(5); dataSource.setMaxPoolSize(20); dataSource.setProperties(props);
return dataSource; }
@Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory( @Qualifier("dataSource") DataSource ds ) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("MilliService"); factoryBean.setDataSource(ds); factoryBean.setPersistenceProviderClass(PersistenceProvider.class); factoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver()); factoryBean.setValidationMode(ValidationMode.NONE); factoryBean.setPackagesToScan("ru.milli.app.persistence"); factoryBean.getJpaPropertyMap().put("eclipselink.weaving", Boolean.FALSE.toString()); factoryBean.getJpaPropertyMap().put("eclipselink.allow-zero-id", Boolean.TRUE.toString());
return factoryBean; }
@Bean public JpaTransactionManager transactionManager( @Qualifier("entityManagerFactory") EntityManagerFactory factory ) throws PropertyVetoException { JpaTransactionManager manager = new JpaTransactionManager(); manager.setEntityManagerFactory(factory); return manager; } }
Для сервлетов там обычные rest-сервисы на аннотациях @RestController.
Конфиг web.xml:

mishka
ru.milli.CleanupContextListener
webportal org.springframework.web.servlet.DispatcherServlet
rest org.springframework.web.servlet.DispatcherServlet
rest /rest/*
webportal *.html
webportal /image.jpeg
500 /WEB-INF/jsp/error.jsp
404 /error.html
/WEB-INF/jsp/start.jsp
http://www.springframework.org/tags /WEB-INF/tld/spring.tld http://www.springframework.org/tags/form /WEB-INF/tld/spring-form.tld


Ответ

Проблема в том, что вы создаёте 2 DispatcherServlet, и в оба включаете application-context.xml. Согласно документации
A web application can define any number of DispatcherServlets. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc.
У каждого DispatcherServlet будет свой контекст Spring, а значит, бины для каждого будут создаваться по отдельности. Тег объединяет текущий конфиг с содержимым импортируемого конфига. Получается, в конфиге каждого сервлета будет объявлен свой пул соединений, и при запуске приложения он создастся два раза.
Решить это можно, создав root контекст с бинами, необходимыми всем дочерним контекстам. Делается это при помощи добавления ContextLoaderListener в web.xml
org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:/path/to/application-context.xml
Все бины, определённые в root контексте, будут видны в дочерних (web application) контекстах. При этом дочерний контекст может переопределить бин из родительского контекста (объявив свой бин с таким же id), поэтому включать application-context.xml в конфиг каждого сервлета при такой конфигурации не нужно.