1. ความปลอดภัย คือ ทำให้สามารถควบคุมการเข้าถึง การเรียกใช้ และการดึงข้อมูลที่สำคัญ หรือเป็นความลับ
รวมถึงการกำหนดข้อจำกัดต่าง ๆ
2. การทำเป็น service กลาง ซึ่งทำให้ไม่ต้องเขียน service ขึ้นมาใหม่บ่อย ๆ ในรูปแบบงานที่คล้าย ๆ กันเกิดขึ้นใหม่
และเป็นการแยก interface ทำให้สามารถ แก้ไข หรือ เปลีี่ยนแปลง interface ได้ตลอดเวลาโดยไม่กระทบ
ที่เหลือคิดไม่ออก แล้ว ไว้ว่าง ๆ มาเขียนข้อดีเพิ่มให้ครับ ^^'
ตัวอย่างโดยใช้ xml ทำการ config บน spring framework
http://static.springsource.org/spring/docs/2.0.4/reference/remoting.html
บทความถัดไป
rmi remote client on spring framework by annotation
เรามาเปลี่ยนจาก xml เป็น annotation กัน เริ่มจาก
project/WebContent/WEB-INF/web.xml
MUWAHOBack contextConfigLocation classpath:conf/applicationContext.xml org.springframework.web.context.ContextLoaderListener org.springframework.web.context.request.RequestContextListener 30 index.jsp
มาถึง config service file
project\src\conf\applicationContext.xml
<context:annotation-config/> <context:component-scan base-package="com.company.project.service" /> <import resource="/rmiContext.xml" />
อันนี้แยกในส่วน rmi ออกมาเป็น
project\src\conf\rmiContext.xml
มาถึงส่วนสำคัญในการประกาศ service rmi
ส่วนแรกจะเป็น Application Context ที่ประกาศเป็นตัวเริ่มต้น เพื่อให้ reuse ได้
project\src\com\company\spring\context\ApplicationContextProvider.java
package com.company.spring.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public abstract class ApplicationContextProvider implements
ApplicationContextAware, BeanFactoryPostProcessor, BeanPostProcessor,
DisposableBean {
private ApplicationContext context;
public ApplicationContext getContext() {
return context;
}
@Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
this.context = context;
}
}
ต่อมาเป็นในส่วนที่ทำเพื่อประกาศ Annotation เราจะนำ Annotation ตัวนี้ไปแปะไว้
บน Class implement ที่เราต้องการประกาศให้เป็น service rmi
project\src\com\company\spring\remoting\RmiServer.java
package com.company.spring.remoting;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
@Target( { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RmiServer {
String name() default "";
Class<?> serviceInterface();
}
ส่วนต่อไป ทำการผูก service ที่ประกาศ Annotation @RmiServer เพื่อประกาศ
service ให้ใช้บริการ rmi ได้โดยผูกเข้ากับ Bean factory ของ Spring
project\src\com\company\spring\remoting\RemoteAnnotationBeanFactoryPostProcessor.java
package com.company.spring.remoting;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.remoting.rmi.RmiServiceExporter;
import org.springframework.remoting.support.RemoteExporter;
import com.company.spring.context.ApplicationContextProvider;
public class RemoteAnnotationBeanFactoryPostProcessor extends
ApplicationContextProvider {
private String basePackage;
private List<String> remoteExporterNames = new ArrayList<String>();
@Override
public Object postProcessBeforeInitialization(Object obj, String beanName)
throws BeansException {
System.out
.println(" RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeforeInitialization ");
System.out.println(" >> Bean name : " + beanName);
System.out.println(" >> Class name : " + obj);
return obj;
}
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out
.println(" RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeanFactory ");
for (String beanName : beanFactory.getBeanDefinitionNames()) {
System.out.println(" BeanDefinitionNames : " + beanName);
BeanDefinition beanDefinition = beanFactory
.getBeanDefinition(beanName);
// Ignore abstract bean! and empty beans
if (beanDefinition.isAbstract()
|| beanDefinition.getBeanClassName() == null
|| beanDefinition.getBeanClassName().indexOf(basePackage) == -1) {
continue;
}
try {
RmiServer remote = AnnotationUtils.findAnnotation(Class
.forName(beanDefinition.getBeanClassName()),
RmiServer.class);
if (remote == null) {
continue;
}
String remoteExporterName = getRmiServiceBeanName(remote);
System.out.println(" Register Singleton RemoteExporterName : "
+ remoteExporterName);
RemoteExporter remoteExporter = createRemoteExporter(remote);
beanFactory.registerSingleton(remoteExporterName,
remoteExporter);
remoteExporterNames.add(remoteExporterName);
} catch (ClassNotFoundException e) {
throw new FatalBeanException("No class for name " + beanName, e);
}
}
}
private String getRmiServiceBeanName(RmiServer remote) {
return "/" + remote.serviceInterface().getSimpleName();
}
private RemoteExporter createRemoteExporter(RmiServer remote) {
RmiServiceExporter remoteExporter = new RmiServiceExporter();
remoteExporter.setServiceInterface(remote.serviceInterface());
remoteExporter
.setServiceName(remote.serviceInterface().getSimpleName());
return remoteExporter;
}
@Override
public Object postProcessAfterInitialization(Object obj, String beanName)
throws BeansException {
System.out
.println(" RemoteAnnotationBeanFactoryPostProcessor >> postProcessAfterInitialization ");
System.out.println(" >> Bean name : " + beanName);
System.out.println(" >> Class name : " + obj);
Class<?> targetClass = null;
Object _obj = obj;
while (_obj instanceof Advised) {
Advised advised = (Advised) _obj;
try {
_obj = advised.getTargetSource().getTarget();
} catch (Exception e) {
throw new FatalBeanException(
"Exception initializing RmiServiceExporter", e);
}
}
targetClass = _obj.getClass();
RmiServer remote = AnnotationUtils.findAnnotation(targetClass,
RmiServer.class);
if (remote == null) {
return obj;
}
try {
RmiServiceExporter remoteExporter = (RmiServiceExporter) getContext()
.getBean(getRmiServiceBeanName(remote));
remoteExporter.setService(obj);
Registry registry = getContext().getBean("rmiRegistry",
Registry.class);
remoteExporter.setRegistry(registry);
remoteExporter.afterPropertiesSet();
System.out.println("Create remote service success " + "with name "
+ remote.serviceInterface().getSimpleName()
+ " with RMI registry: " + registry + ".");
} catch (Exception e) {
throw new FatalBeanException(
"Exception initializing RmiServiceExporter", e);
}
return obj;
}
@Override
public void destroy() throws Exception {
System.out
.println(" RemoteAnnotationBeanFactoryPostProcessor >> destroy ");
for (String remoteExporterName : remoteExporterNames) {
getContext().getBean(remoteExporterName, RmiServiceExporter.class)
.destroy();
}
}
/*
* auto-create get-set method.
*/
public String getBasePackage() {
return basePackage;
}
public void setBasePackage(String basePackage) {
this.basePackage = basePackage;
}
public List<String> getRemoteExporterNames() {
return remoteExporterNames;
}
public void setRemoteExporterNames(List<String> remoteExporterNames) {
this.remoteExporterNames = remoteExporterNames;
}
}
========================================
ส่วนต่อไปคือเริ่มทำ service ที่ใช้งานจริงๆ กันเลยดีกว่าเริ่มด้วย
Interface service
project\src\com\company\project\service\ItestService.java
package com.company.project.service;
public interface ItestService {
public String getPrefixHello(String str);
}
project\src\com\company\project\service\TestService.javaImplements service
package com.company.project.service;
import org.springframework.stereotype.Service;
import com.company.spring.remoting.RmiServer;
@RmiServer(serviceInterface = ItestService.class)
@Service
public class TestService implements ItestService {
@Override
public String getPrefixHello(String str) {
System.out.println(" TestService >> getPrefixHello ");
return "Hello 123 : "+str;
}
}
หลังจากนั้นก็ลอง test service ดูโดยทำตัว test ขึ้นมา
project\src\com\company\project\test\TestServiceTest.java
package com.company.project.test;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.company.project.service.ItestService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/conf/applicationContext.xml"})
public class TestServiceTest {
@Autowired
private ItestService itestService;
public void setItestService(ItestService itestService) {
this.itestService = itestService;
}
@Before
public void setUp() throws Exception {
System.out.println("setUp");
}
@After
public void tearDown() throws Exception {
System.out.println("tearDown");
}
@Test
public void testGetData() {
System.out.println("testGetData");
String outStr = "";
try{
outStr = this.itestService.getPrefixHello("test 123 d^^");
System.out.println("result : " + outStr);
}catch(Exception e){
System.out.println("ERROR : " + e);
e.printStackTrace();
}
}
}
log ที่ได้หลังจาก run test
12 พ.ค. 2553 11:06:38 org.springframework.test.context.TestContextManager retrieveTestExecutionListeners
INFO: @TestExecutionListeners is not present for class [class com.company.project.test.TestServiceTest]: using defaults.
12 พ.ค. 2553 11:06:38 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [conf/applicationContext.xml]
12 พ.ค. 2553 11:06:39 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [conf/rmiContext.xml]
12 พ.ค. 2553 11:06:39 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.GenericApplicationContext@7ffe01: startup date [Wed May 12 11:06:39 ICT 2010]; root of context hierarchy
12 พ.ค. 2553 11:06:39 org.springframework.remoting.rmi.RmiRegistryFactoryBean getRegistry
INFO: Looking for RMI registry at port '1019'
12 พ.ค. 2553 11:06:40 org.springframework.remoting.rmi.RmiRegistryFactoryBean getRegistry
INFO: Could not detect RMI registry - creating new one
RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeanFactory
BeanDefinitionNames : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalRequiredAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalCommonAnnotationProcessor
BeanDefinitionNames : testService
Register Singleton RemoteExporterName : /ItestService
BeanDefinitionNames : rmiRegistry
BeanDefinitionNames : appContextProvider
BeanDefinitionNames : com.company.spring.remoting.RemoteAnnotationBeanFactoryPostProcessor#0
12 พ.ค. 2553 11:06:40 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@ff057f: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,testService,rmiRegistry,appContextProvider,com.company.spring.remoting.RemoteAnnotationBeanFactoryPostProcessor#0]; root of factory hierarchy
RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeforeInitialization
>> Bean name : testService
>> Class name : com.company.project.service.TestService@15a6029
RemoteAnnotationBeanFactoryPostProcessor >> postProcessAfterInitialization
>> Bean name : testService
>> Class name : com.company.project.service.TestService@15a6029
12 พ.ค. 2553 11:06:40 org.springframework.remoting.rmi.RmiServiceExporter prepare
INFO: Binding service 'ItestService' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[10.239.20.141:1019](local),objID:[0:0:0, 0]]]]
Create remote service success with name ItestService with RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[10.239.20.141:1019](local),objID:[0:0:0, 0]]]].
RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeforeInitialization
>> Bean name : com.company.project.test.TestServiceTest
>> Class name : com.company.project.test.TestServiceTest@f9c40
RemoteAnnotationBeanFactoryPostProcessor >> postProcessAfterInitialization
>> Bean name : com.company.project.test.TestServiceTest
>> Class name : com.company.project.test.TestServiceTest@f9c40
setUp
testGetData
TestService >> getPrefixHello
result : Hello 123 : test 123 d^^
tearDown
12 พ.ค. 2553 11:06:40 org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.springframework.context.support.GenericApplicationContext@7ffe01: startup date [Wed May 12 11:06:39 ICT 2010]; root of context hierarchy
12 พ.ค. 2553 11:06:40 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@ff057f: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,testService,rmiRegistry,appContextProvider,com.company.spring.remoting.RemoteAnnotationBeanFactoryPostProcessor#0]; root of factory hierarchy
12 พ.ค. 2553 11:06:40 org.springframework.remoting.rmi.RmiServiceExporter destroy
INFO: Unbinding RMI service 'ItestService' from registry at port '1099'
12 พ.ค. 2553 11:06:40 org.springframework.remoting.rmi.RmiRegistryFactoryBean destroy
INFO: Unexporting RMI registry
RemoteAnnotationBeanFactoryPostProcessor >> destroy
ลอง run บน env server tomcat6
12 พ.ค. 2553 11:06:01 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:TestRmiAnnoServer' did not find a matching property.
12 พ.ค. 2553 11:06:01 org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jre6\bin;.;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:/Program Files/Java/jre6/bin/client;C:/Program Files/Java/jre6/bin;C:\Program Files\CA\SC\CAWIN\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32\wbem;.;C:\Program Files\Java\jdk1.6.0_11\bin;C:\Program Files\Common Files\NetSarang;C:\Program Files\Java\jdk1.6.0_11\BIN;C:\ant\bin;C:\Oracle9i\bin;C:\Program Files\Oracle\jre\1.3.1\bin;C:\Program Files\Oracle\jre\1.1.8\bin;C:\Ora6i\bin;C:\ORANT\bin;C:\TUXEDO\bin;C:\Program Files\SQLLIB\BIN;C:\Program Files\SQLLIB\HELP;C:\Ora6i\jdk\bin;C:\ORAWIN\Bin;C:\Program Files\cvsnt;;C:\Program Files\Common Files\Compuware;C:\PROGRA~1\CA\SC\CAM\bin;C:\Program Files\CA\DSM\bin;C:\ORAWIN\BIN;C:\ORANT\BIN;C:\CUBICS3T;C:\TUXEDO\BIN;
12 พ.ค. 2553 11:06:01 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
12 พ.ค. 2553 11:06:01 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 801 ms
12 พ.ค. 2553 11:06:01 org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
12 พ.ค. 2553 11:06:01 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.18
12 พ.ค. 2553 11:06:02 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
12 พ.ค. 2553 11:06:02 org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization started
12 พ.ค. 2553 11:06:02 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing Root WebApplicationContext: startup date [Wed May 12 11:06:02 ICT 2010]; root of context hierarchy
12 พ.ค. 2553 11:06:03 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [conf/applicationContext.xml]
12 พ.ค. 2553 11:06:03 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [conf/rmiContext.xml]
12 พ.ค. 2553 11:06:04 org.springframework.remoting.rmi.RmiRegistryFactoryBean getRegistry
INFO: Looking for RMI registry at port '1019'
12 พ.ค. 2553 11:06:05 org.springframework.remoting.rmi.RmiRegistryFactoryBean getRegistry
INFO: Could not detect RMI registry - creating new one
RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeanFactory
BeanDefinitionNames : org.springframework.context.annotation.internalConfigurationAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalAutowiredAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalRequiredAnnotationProcessor
BeanDefinitionNames : org.springframework.context.annotation.internalCommonAnnotationProcessor
BeanDefinitionNames : testService
Register Singleton RemoteExporterName : /ItestService
BeanDefinitionNames : rmiRegistry
BeanDefinitionNames : appContextProvider
BeanDefinitionNames : com.company.spring.remoting.RemoteAnnotationBeanFactoryPostProcessor#0
12 พ.ค. 2553 11:06:05 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e1dadb: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,testService,rmiRegistry,appContextProvider,com.company.spring.remoting.RemoteAnnotationBeanFactoryPostProcessor#0]; root of factory hierarchy
RemoteAnnotationBeanFactoryPostProcessor >> postProcessBeforeInitialization
>> Bean name : testService
>> Class name : com.company.project.service.TestService@1777b1
RemoteAnnotationBeanFactoryPostProcessor >> postProcessAfterInitialization
>> Bean name : testService
>> Class name : com.company.project.service.TestService@1777b1
12 พ.ค. 2553 11:06:05 org.springframework.remoting.rmi.RmiServiceExporter prepare
INFO: Binding service 'ItestService' to RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[10.239.20.141:1019](local),objID:[0:0:0, 0]]]]
Create remote service success with name ItestService with RMI registry: RegistryImpl[UnicastServerRef [liveRef: [endpoint:[10.239.20.141:1019](local),objID:[0:0:0, 0]]]].
12 พ.ค. 2553 11:06:05 org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 2516 ms
12 พ.ค. 2553 11:06:05 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
12 พ.ค. 2553 11:06:05 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
12 พ.ค. 2553 11:06:05 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/47 config=null
12 พ.ค. 2553 11:06:05 org.apache.catalina.startup.Catalina start
INFO: Server startup in 4107 ms
ไม่มีความคิดเห็น:
แสดงความคิดเห็น