芪æãªãããã©ã人ã®çãããããã«ã¡ã¯ã 3幎éãSpringã䜿çšãããããžã§ã¯ãã«åãçµãã§ããŸããã ç§ã¯ãã€ããããã©ã®ããã«å éšã«é 眮ãããŠããããç解ããããšã«èå³ããããŸããã Springã®å éšæ§é ã«é¢ããèšäºãæ€çŽ¢ããŸããããæ®å¿µãªããäœãèŠã€ãããŸããã§ããã
Springã®å éšæ§é ã«èå³ããã人ã¯èª°ã§ãç«ããé¡ãããŸãã
ãã®å³ã¯ãApplicationContextãäžããäž»ãªæ®µéã瀺ããŠããŸãã ãã®æçš¿ã§ã¯ããããã®å段éã«çŠç¹ãåœãŠãŸãã ããã€ãã®æ®µéã詳现ã«æ€èšããããã€ãã®æ®µéãäžè¬çãªçšèªã§èª¬æããŸãã
1.èšå®ã®è§£æãšBeanDefinitionã®äœæ
æ¥ã®4çªç®ã®ããŒãžã§ã³ã®ãªãªãŒã¹åŸãã³ã³ããã¹ããæ§æãã4ã€ã®æ¹æ³ããããŸãã
- XMLæ§æ-ClassPathXmlApplicationContextïŒãcontext.xmlãïŒ
- ã¹ãã£ã³ããããã±ãŒãžã瀺ã泚éã«ããæ§æ-AnnotationConfigApplicationContextïŒâ package.nameâïŒ
- ã¢ãããŒã·ã§ã³@Configuration -AnnotationConfigApplicationContextïŒJavaConfig.classïŒã§ããŒã¯ãããã¯ã©ã¹ïŒãŸãã¯ã¯ã©ã¹ã®é åïŒã瀺ãã¢ãããŒã·ã§ã³ãä»ããæ§æã ãã®æ§ææ¹æ³ã¯JavaConfigãšåŒã°ããŸãã
- Groovyæ§æ-GenericGroovyApplicationContextïŒãcontext.groovyãïŒ
4ã€ãã¹ãŠã®æ¹æ³ã¯ã ããã§éåžžã«ããæžãããŠããŸã ã
æåã®æ®µéã®ç®æšã¯ããã¹ãŠã®BeanDefinitionãäœæããããšã§ãã BeanDefinitionã¯ãå°æ¥ã®Beanã®ã¡ã¿ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããç¹å¥ãªã€ã³ã¿ãŒãã§ãŒã¹ã§ãã 䜿çšããŠããæ§æã«å¿ããŠã1ã€ãŸãã¯å¥ã®æ§æ解æã¡ã«ããºã ã䜿çšãããŸãã
XMLèšå®
Xmlæ§æã®å Žåã BeanDefinitionReaderã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããã¯ã©ã¹XmlBeanDefinitionReaderã䜿çšãããŸãã ããã§ã¯ãã¹ãŠãéæã§ãã XmlBeanDefinitionReaderã¯InputStreamãåãåãã DefaultDocumentLoaderãä»ããŠããã¥ã¡ã³ããããŒãããŸãã 次ã«ãããã¥ã¡ã³ãã®åèŠçŽ ãåŠçãããããããã³ã®å Žåãå ¥åãããããŒã¿ïŒidãnameãclassãaliasãinit-methodãdestroy-methodãªã©ïŒã«åºã¥ããŠBeanDefinitionãäœæãããŸãã åBeanDefinitionã¯ãããã«é 眮ãããŸãã ãããã¯DefaultListableBeanFactoryã¯ã©ã¹ã«ä¿åãããŸãã ã³ãŒãã§ã¯ãMapã¯æ¬¡ã®ããã«ãªããŸãã
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
ã¹ãã£ã³ãŸãã¯JavaConfigã®ããã±ãŒãžã瀺ã泚éã«ããæ§æ
ã¹ãã£ã³ãŸãã¯JavaConfigã®ããã±ãŒãžã瀺ã泚éã«ããæ§æã¯ãxmlã«ããæ§æãšã¯æ ¹æ¬çã«ç°ãªããŸãã ã©ã¡ãã®å Žåãã AnnotationConfigApplicationContextã¯ã©ã¹ã䜿çšãããŸãã
new AnnotationConfigApplicationContext(JavaConfig.class);
ãŸãã¯
new AnnotationConfigApplicationContext(âpackage.nameâ);
AnnotationConfigApplicationContextã®å éšãèŠããšã2ã€ã®ãã£ãŒã«ãã衚瀺ãããŸãã
private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner;
ClassPathBeanDefinitionScannerã¯ãæå®ãããããã±ãŒãžãã¹ãã£ã³ããŠã @ Componentã¢ãããŒã·ã§ã³ïŒãŸãã¯@Componentãå«ããã®ä»ã®ã¢ãããŒã·ã§ã³ïŒã§ããŒã¯ãããã¯ã©ã¹ãæ¢ããŸãã èŠã€ãã£ãã¯ã©ã¹ã解æãããBeanDefinitionãäœæãããŸãã
ã¹ãã£ã³ãå®è¡ããã«ã¯ãã¹ãã£ã³çšã®ããã±ãŒãžãæ§æã§æå®ããå¿ èŠããããŸãã
@ComponentScan({"package.name"})
ãŸãã¯
<context:component-scan base-package="package.name"/>
AnnotatedBeanDefinitionReaderã¯ããã€ãã®ã¹ãããã§æ©èœããŸãã
- æåã®ã¹ãããã¯ãããã«è§£æããããã«ãã¹ãŠã®@Configurationãç»é²ããããšã§ãã æ§æã§æ¡ä»¶ã䜿çšãããŠããå Žåã æ¡ä»¶ã trueãè¿ãæ§æã®ã¿ãç»é²ãããŸãã æ¡ä»¶ä»ã泚éã¯ãæ¥ã®4çªç®ã®ããŒãžã§ã³ã«ç»å ŽããŸããã ã³ã³ããã¹ããäžãããšãã«ããã³/æ§æãäœæãããã©ããã決å®ããå¿ èŠãããå Žåã«äœ¿çšãããŸãã ãŸãã決å®ã¯ç¹å¥ãªã¯ã©ã¹ã«ãã£ãŠè¡ããã Conditionã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããå¿ èŠããããŸãã
- 2çªç®ã®ã¹ãããã¯ãç¹å¥ãªBeanFactoryPostProcessor ãã€ãŸãBeanDefinitionRegistryPostProcessorãç»é²ããããšã§ããããã¯ã ConfigurationClassParserã¯ã©ã¹ã䜿çšããŠãJavaConfigã解æãã BeanDefinitionãäœæããŸã ã
Groovyã®æ§æ
ãã®æ§æã¯ããã¡ã€ã«ãXMLã§ã¯ãªãGroovyã§ããããšãé€ããŠãXmlãä»ããæ§æãšéåžžã«äŒŒãŠããŸãã GroovyBeanDefinitionReaderã¯ã©ã¹ã¯ ãgroovyæ§æã®èªã¿åããšè§£æãåŠçããŸãã
2.äœæãããBeanDefinitionãæ§æãã
æåã®æ®µéã®åŸã BeanDefinitionãæ ŒçŽãããããããããŸã ã Springã¢ãŒããã¯ãã£ã¯ãBeanãå®éã«äœæãããåã«ããã®Beanã«åœ±é¿ãäžããããšãã§ããããã«æ§ç¯ãããŠããŸããã€ãŸããã¯ã©ã¹ã¡ã¿ããŒã¿ã«ã¢ã¯ã»ã¹ã§ããŸãã ãããè¡ãããã«ãç¹å¥ãªã€ã³ã¿ãŒãã§ãŒã¹BeanFactoryPostProcessorããã ããããå®è£ ããŠãäœæãããBeanDefinitionã«ã¢ã¯ã»ã¹ããããããå€æŽã§ããŸãã ãã®ã€ã³ã¿ãŒãã§ãŒã¹ã«ã¯ã¡ãœããã1ã€ãããããŸããã
public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
postProcessBeanFactoryã¡ãœããã¯ã ConfigurableListableBeanFactoryãã©ã¡ãŒã¿ãŒãåãå ¥ããŸãã ãã®ãã¡ã¯ããªã«ã¯ããã¹ãŠã®BeanDefinitionNamesãååŸããç¹å®ã®ååã®ç¹å®ã®ã¡ã¿ããŒã¿ã®BeanDefinitionãååŸããgetBeanDefinitionNamesãå«ãå€ãã®äŸ¿å©ãªã¡ãœãããå«ãŸããŠããŸãã
BeanFactoryPostProcessorã€ã³ã¿ãŒãã§ãŒã¹ã®ãã€ãã£ãå®è£ ã®1ã€ãèŠãŠã¿ãŸãããã éåžžãããŒã¿ããŒã¹ã«æ¥ç¶ããããã®èšå®ã¯å¥ã®ããããã£ãã¡ã€ã«ã«è»¢éããã PropertySourcesPlaceholderConfigurerã䜿çšããŠèªã¿èŸŒãŸãããããã®å€ãç®çã®ãã£ãŒã«ãã«æ¿å ¥ããŸãã æ³šå ¥ã¯ããŒã«ãã£ãŠè¡ããããããBeanã®ã€ã³ã¹ã¿ã³ã¹ãäœæããåã«ããã®ããŒãããããã£ãã¡ã€ã«ã®å€èªäœã«çœ®ãæããå¿ èŠããããŸãã ãã®çœ®æã¯ã BeanFactoryPostProcessorã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããã¯ã©ã¹ã§çºçããŸãã ãã®ã¯ã©ã¹ã®ååã¯PropertySourcesPlaceholderConfigurerã§ãã ããã»ã¹å šäœãäžã®å³ã«ç€ºããŸãã
ããã§äœãèµ·ãã£ãŠããã®ãããäžåºŠèŠãŠã¿ãŸãããã ClassNameã¯ã©ã¹ã®BeanDefinitionããããŸãã ã¯ã©ã¹ã³ãŒãã以äžã«ç€ºããŸãã
@Component public class ClassName { @Value("${host}") private String host; @Value("${user}") private String user; @Value("${password}") private String password; @Value("${port}") private Integer port; }
PropertySourcesPlaceholderConfigurerããã®BeanDefinitionãåŠçããªãå ŽåãClassNameã®ã€ã³ã¹ã¿ã³ã¹ãäœæããåŸãå€ã$ {host}ãããã¹ããã£ãŒã«ãã«æ³šå ¥ãããŸãïŒå¯Ÿå¿ããå€ãæ®ãã®ãã£ãŒã«ãã«æ³šå ¥ãããŸãïŒã PropertySourcesPlaceholderConfigurerãåŒãç¶ããã®BeanDefinitionãåŠçããå ŽåãåŠçåŸããã®ã¯ã©ã¹ã®ã¡ã¿ããŒã¿ã¯æ¬¡ã®ããã«ãªããŸãã
@Component public class ClassName { @Value("127.0.0.1") private String host; @Value("root") private String user; @Value("root") private String password; @Value("27017") private Integer port; }
ãããã£ãŠããããã®ãã£ãŒã«ãã«ã¯æ£ããå€ãæ¿å ¥ãããŸãã
äœæãããBeanDefinitionã®èšå®ã«ãŒãã«PropertySourcesPlaceholderConfigurerãè¿œå ããã«ã¯ã次ã®ãããããå®è¡ããå¿ èŠããããŸãã
XMLæ§æçšã
<context:property-placeholder location="property.properties" />
JavaConfigã®å Žåã
@Configuration @PropertySource("classpath:property.properties") public class DevConfig { @Bean public static PropertySourcesPlaceholderConfigurer configurer() { return new PropertySourcesPlaceholderConfigurer(); } }
PropertySourcesPlaceholderConfigurerã¯éçãšããŠå®£èšããå¿ èŠããããŸãã éçã§ãªãå Žåã @ Configurationã¯ã©ã¹å ã§@ Valueã䜿çšããããšãããŸã§ããã¹ãŠãæ©èœããŸãã
3.ã«ã¹ã¿ã FactoryBeanã®äœæ
FactoryBeanã¯ãã¿ã€ãBeanã®äœæããã»ã¹ãå§ä»»ã§ããæ±çšã€ã³ã¿ãŒãã§ãŒã¹ã§ãã æ§æãxmlã®ã¿ã§ãã£ãåœæãéçºè ã¯Beanã®äœæããã»ã¹ãå¶åŸ¡ã§ããã¡ã«ããºã ãå¿ èŠãšããŠããŸããã ããããŸãã«ãã®ã€ã³ã¿ãŒãã§ãŒã¹ã®ç®çã§ãã åé¡ãããããç解ããããã«ãXMLæ§æã®äŸã瀺ããŸãã
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="redColor" scope="prototype" class="java.awt.Color"> <constructor-arg name="r" value="255" /> <constructor-arg name="g" value="0" /> <constructor-arg name="b" value="0" /> </bean> </beans>
äžèŠããã¹ãŠãæ£åžžã§ãããåââé¡ã¯ãããŸããã ããããå¥ã®è²ãå¿ èŠãªå Žåã¯ã©ãã§ããããïŒ å¥ã®BeanãäœæããŸããïŒ è³ªåãªãã
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="redColor" scope="prototype" class="java.awt.Color"> <constructor-arg name="r" value="255" /> <constructor-arg name="g" value="0" /> <constructor-arg name="b" value="0" /> </bean> <bean id="green" scope="prototype" class="java.awt.Color"> <constructor-arg name="r" value="0" /> <constructor-arg name="g" value="255" /> <constructor-arg name="b" value="0" /> </bean> </beans>
ããããæ¯åã©ã³ãã ãªè²ãå¿ èŠãªå Žåã¯ã©ãã§ãããã ãããFactoryBeanã€ã³ã¿ãŒãã§ãŒã¹ã®å©ããšãªããŸãã
ãã¹ãŠã®ã¿ã€ãBean- Colorã®äœæãæ åœãããã¡ã¯ããªãŒãäœæããŸãããã
package com.malahov.factorybean; import org.springframework.beans.factory.FactoryBean; import org.springframework.stereotype.Component; import java.awt.*; import java.util.Random; /** * User: malahov * Date: 18.04.14 * Time: 15:59 */ public class ColorFactory implements FactoryBean<Color> { @Override public Color getObject() throws Exception { Random random = new Random(); Color color = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)); return color; } @Override public Class<?> getObjectType() { return Color.class; } @Override public boolean isSingleton() { return false; } }
ãããxmlã«è¿œå ãã以åã«å®£èšããã¿ã€ãbeans- Colorãåé€ããŸãã
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="colorFactory" class="com.malahov.temp.ColorFactory"></bean> </beans>
ããã§ã Color.classåã®Beanã®äœæã¯ColorFactoryã«ãã£ãŠå§ä»»ãããæ°ããBeanãäœæããããã³ã«getObjectã¡ãœããã䜿çšãããŸãã
JavaConfigã䜿çšãããŠãŒã¶ãŒã«ãšã£ãŠããã®ã€ã³ã¿ãŒãã§ãŒã¹ã¯ãŸã£ãã圹ã«ç«ã¡ãŸããã
4. Beanã€ã³ã¹ã¿ã³ã¹ã®äœæ
BeanFactoryã¯Beanã®ã€ã³ã¹ã¿ã³ã¹ãäœæããå¿ èŠã«å¿ããŠãããã«ã¹ã¿ã FactoryBeanã«å§ä»»ããŸãã Beanã€ã³ã¹ã¿ã³ã¹ã¯ã以åã«äœæãããBeanDefinitionã«åºã¥ããŠäœæãããŸã ã
5.äœæãããBeanã®ã»ããã¢ãã
BeanPostProcessorã€ã³ã¿ãŒãã§ãŒã¹ã䜿çšãããšãBeanãã³ã³ããã«å ¥ãåã«ãèšå®ããã»ã¹ã«äŸµå ¥ããããšãã§ããŸã ã ã€ã³ã¿ãŒãã§ã€ã¹ã«ã¯ããã€ãã®ã¡ãœããããããŸãã
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
ãã³ããšã«äž¡æ¹ã®ã¡ãœãããåŒã³åºãããŸãã ã©ã¡ãã®ã¡ãœããã«ããŸã£ããåããã©ã¡ãŒã¿ãŒããããŸãã å¯äžã®éãã¯ãããããåŒã³åºãããé åºã§ãã æåã®ã¡ãœããã¯initã¡ãœããã®åã«åŒã³åºããã2çªç®ã®ã¡ãœããã¯ãã®åŸã«åŒã³åºãããŸãã ãã®æ®µéã§ãBeanã€ã³ã¹ã¿ã³ã¹ã¯ãã§ã«äœæãããŠãããåæ§æãããŠããããšãç解ããããšãéèŠã§ãã 2ã€ã®éèŠãªãã€ã³ãããããŸãã
- äž¡æ¹ã®ã¡ãœããã¯æçµçã«Beanãè¿ãå¿ èŠããããŸãã ã¡ãœããã§nullãè¿ãå Žåãã³ã³ããã¹ããããã®ãã³ãåãåããšnullã«ãªããŸãããã¹ãŠã®ãã³ã¯binpostprocessorãééãããããã³ã³ããã¹ããäžããåŸããã³ããªã¯ãšã¹ããããšãnullã®æå³ã§figsãåãåããŸãã
- ãªããžã§ã¯ãã«ãããã·ãäœæããå Žåã¯ãinitã¡ãœãããåŒã³åºããåŸã«ãããè¡ãã®ãäžè¬çã§ããããšã«æ³šæããŠãã ãããã€ãŸãã postProcessAfterInitializationã¡ãœããã§ãããè¡ãå¿ èŠããããŸãã
ãã¥ãŒãã³ã°ããã»ã¹ã次ã®å³ã«ç€ºããŸãã BeanPostProcessorãåŒã³åºãããé åºã¯äžæã§ãããããããé çªã«å®è¡ãããããšã¯ç¢ºãã§ãã
ãããäœã®ããã§ããããããããç解ããããã«ãäŸãèŠãŠã¿ãŸãããã
倧èŠæš¡ãããžã§ã¯ããéçºããå ŽåãååãšããŠãããŒã ã¯ããã€ãã®ã°ã«ãŒãã«åå²ãããŸãã ããšãã°ãéçºè ã®æåã®ã°ã«ãŒãã¯ãããžã§ã¯ãã®ã€ã³ãã©ã¹ãã©ã¯ãã£ãèšè¿°ããŠããã2çªç®ã®ã°ã«ãŒãã¯æåã®ã°ã«ãŒãã®ææã䜿çšããŠããžãã¹ããžãã¯ãèšè¿°ããŠããŸãã 2çªç®ã®ã°ã«ãŒãããããã€ãã®å€ïŒããšãã°ä¹±æ°ïŒããã³ã«æ¿å ¥ã§ããæ©èœãå¿ èŠãšããŠãããšããŸãã
æåã®æ®µéã§ãå€ãæ¿å ¥ããå¿ èŠãããã¯ã©ã¹ã®ãã£ãŒã«ããããŒã¯ãã泚éãäœæãããŸãã
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectRandomInt { int min() default 0; int max() default 10; }
ããã©ã«ãã§ã¯ãä¹±æ°ã®ç¯å²ã¯0ã10ã§ãã
次ã«ããã®ã¢ãããŒã·ã§ã³ã®ãã³ãã©ãŒãã€ãŸãã InjectRandomIntã¢ãããŒã·ã§ã³ãåŠçããBeanPostProcessorå®è£ ãäœæããå¿ èŠããããŸãã
@Component public class InjectRandomIntBeanPostProcessor implements BeanPostProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(InjectRandomIntBeanPostProcessor.class); @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { LOGGER.info("postProcessBeforeInitialization::beanName = {}, beanClass = {}", beanName, bean.getClass().getSimpleName()); Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(InjectRandomInt.class)) { field.setAccessible(true); InjectRandomInt annotation = field.getAnnotation(InjectRandomInt.class); ReflectionUtils.setField(field, bean, getRandomIntInRange(annotation.min(), annotation.max())); } } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } private int getRandomIntInRange(int min, int max) { return min + (int)(Math.random() * ((max - min) + 1)); } }
ãã®BeanPostProcessorã®ã³ãŒãã¯éåžžã«ééçã§ãããããããã§ã¯è©³ãã説æããŸããããéèŠãªç¹ã1ã€ãããŸãã
BeanPostProcessorã¯Beanã§ãªããã°ãªããªãããã @ Componentã¢ãããŒã·ã§ã³ã§ããŒã¯ããããéåžžã®BeanãšããŠxmlæ§æã«ç»é²ããŸãã
éçºè ã®æåã®ã°ã«ãŒãã¯ãã®ã¿ã¹ã¯ãå®äºããŸããã ããã§ã2çªç®ã®ã°ã«ãŒãã¯ãããã®éçºã䜿çšã§ããŸãã
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class MyBean { @InjectRandomInt private int value1; @InjectRandomInt(min = 100, max = 200) private int value2; private int value3; @Override public String toString() { return "MyBean{" + "value1=" + value1 + ", value2=" + value2 + ", value3=" + value3 + '}'; } }
ãã®çµæãã³ã³ããã¹ãããååŸãããã¿ã€ãMyBeanã®ãã¹ãŠã®ãã³ã¯ããã§ã«åæåããããã£ãŒã«ãvalue1ããã³value2ã§äœæãããŸãã ãŸãããããã®ãã£ãŒã«ãã«å€ãæ¿å ¥ãã段éã¯ããã³ãã©ã®ãããª@ã¹ã³ãŒããæã£ãŠãããã«äŸåããããšã«æ³šæããŠãã ããã SCOPE_SINGLETON-åæåã¯ãã³ã³ããã¹ããäžãã段éã§1åçºçããŸãã SCOPE_PROTOTYPE-ãªã¯ãšã¹ãã«å¿ããŠæ¯ååæåãå®è¡ãããŸãã 2çªç®ã®å ŽåãBeanã¯ãã¹ãŠã®BeanPostProcessorsãééãããããããã©ãŒãã³ã¹ã«å€§ããªåœ±é¿ãäžããå¯èœæ§ããããŸãã
å®å šãªããã°ã©ã ã³ãŒãã¯ãã¡ãã«ãããŸã ã
EvgenyBorisovã«ç¹ã«æè¬ããŸã ã 圌ã®ã³ãŒã¹ã®ãããã§ãç§ã¯ãã®æçš¿ãæžãããšã«ããŸããã
ãŸããJPoint 2014ããã®åœŒã®ã¬ããŒããèŠãããšããå§ãããŸãã