제로에서 RPC (6) 많은 프레임 워크와 Spring의 비밀

이 장의 내용 :

1. Spring FactoryBean과 InitializingBean의 역할.

2. xsd 파일을 사용자 정의하십시오. 태그를 사용하여 Spring xml 파일을 사용자 정의하십시오.

3. 사용자 지정 레이블 확인을 설정하기 위해 BeanDefinitionParser를 확장하는 프로세스가 사용자 지정 빈이됩니다.

4. 사용자 정의 Bean의 사후 작업은 Netty 서비스 열기 (나중에 설명), 레지스트리 등록 및 기타 조치를 완료합니다.

 

1. Spring FactoryBean과 InitializingBean의 역할.

Spring의 라이프 사이클은 추후 Spring이 별도로 작성 될 때 소개 될 예정입니다. 이제 FactoryBean과 InitializingBean의 두 인터페이스 만 소개합니다.

1. InitializingBean. 호스팅을 위해 클래스 인스턴스화 프로세스를 IOC 컨테이너에 넘길 때 클래스를 인스턴스화 한 후 몇 가지 작업을 수행 할 수 있기를 바랍니다. 이 인터페이스를 구현할 수 있습니다.

그리고 afterPropertiesSet () 메서드에 논리를 작성합니다.

2. FactoryBean. 클래스를 사용자 정의 할 때 다른 객체를 얻고이 클래스에 입력합니다. 이 인터페이스를 사용할 수 있습니다. 이것은 약간 추상적입니다. 예를 들어 특정 장면 : 데코레이터 클래스 (데코레이터 모드). 실제로 로직을 실행하여 무언가를 수행하는 클래스 외부에 래퍼 클래스가 있기를 바랍니다. 이 인터페이스를 사용하여 데코 레이팅 된 클래스 (현재 클래스 자체)와 데코 레이팅 된 클래스 (getObject ()로 얻은 객체)를 바인딩 할 수 있습니다. 그래서 몇 가지 논리를 수행합니다.

Rpc에서이 두 가지 기능을 사용하고 Netty 서비스 열기와 레지스트리 등록을 사후 작업에 넣습니다. 각 인터페이스의 해당 구현 클래스를 장식하기위한 장식 클래스.

/**
 * 
 * <p>Title: ProviderFactoryBean.java</p>  
* <p>Description: </p>  
* @author zhaojunjie  
* @date 2020年3月28日  
* @version 1.0
 */
public class ProviderFactoryBean implements InitializingBean,FactoryBean{

	private Class<?> serviceInterface;
	private Object serviceObject;
	private String servicePort;
	private long timeout;
	private Object serviceProxyObject;
	private String appKey;
	private String groupName;
	private int weight = 1;
	private int workerThread = 10;
	
	@Override
	public Object getObject() throws Exception {
		return serviceObject;
	}

	@Override
	public Class getObjectType() {
		return serviceInterface;
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		//1、开启NettyServer
		System.out.println(this.toString());
		//2、注册到zookeeper注册中心
		List<ProviderService> serviceMetaData = buildProviderServiceInfo();
		RegisterCenter.singleton().registerProvider(serviceMetaData);
	}

	private List<ProviderService> buildProviderServiceInfo() {
		List<ProviderService> providerList = Lists.newArrayList();
		Method[] methods = serviceObject.getClass().getDeclaredMethods();
		for (Method method : methods) {
			ProviderService providerService = new ProviderService();
			providerService.setServiceInterface(serviceInterface);
			providerService.setServiceObject(serviceObject);
			providerService.setServerIp(IPHelper.getCurrentIp());
			providerService.setServicePort(Integer.parseInt(servicePort));
			providerService.setTimeout(timeout);
			providerService.setServiceMethod(method);
			providerService.setWeight(weight);
			providerService.setWorkerThread(workerThread);
			providerService.setAppKey(appKey);
			providerService.setGroupName(groupName);
			providerList.add(providerService);
		}
		return providerList;
	}

	public Class<?> getServiceInterface() {
		return serviceInterface;
	}

	public void setServiceInterface(Class<?> serviceInterface) {
		this.serviceInterface = serviceInterface;
	}

	public Object getServiceObject() {
		return serviceObject;
	}

	public void setServiceObject(Object serviceObject) {
		this.serviceObject = serviceObject;
	}

	public String getServicePort() {
		return servicePort;
	}

	public void setServicePort(String servicePort) {
		this.servicePort = servicePort;
	}

	public long getTimeout() {
		return timeout;
	}

	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}

	public Object getServiceProxyObject() {
		return serviceProxyObject;
	}

	public void setServiceProxyObject(Object serviceProxyObject) {
		this.serviceProxyObject = serviceProxyObject;
	}

	public String getAppKey() {
		return appKey;
	}

	public void setAppKey(String appKey) {
		this.appKey = appKey;
	}

	public String getGroupName() {
		return groupName;
	}

	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}

	public int getWeight() {
		return weight;
	}

	public void setWeight(int weight) {
		this.weight = weight;
	}

	public int getWorkerThread() {
		return workerThread;
	}

	public void setWorkerThread(int workerThread) {
		this.workerThread = workerThread;
	}

	@Override
	public String toString() {
		return "ProviderFactoryBean [serviceInterface=" + serviceInterface + ", serviceObject=" + serviceObject
				+ ", servicePort=" + servicePort + ", timeout=" + timeout + ", serviceProxyObject=" + serviceProxyObject
				+ ", appKey=" + appKey + ", groupName=" + groupName + ", weight=" + weight + ", workerThread="
				+ workerThread + "]";
	}
}

2. xsd 파일을 사용자 정의하십시오. 태그를 사용하여 Spring xml 파일을 사용자 정의하십시오.

1. xsd 파일의 정의. 파일은 resources / META-INF / 디렉토리에 있습니다 (예 : resources / META-INF / back-service.xsd).

xmlns에 정의 된 주소 : http://www.back.com/schema/back-service

요소의 이름을 정의하는 데주의를 기울여야합니다. 구문 분석 할 때이 이름을 기반으로 해당 구문 분석 클래스를 찾습니다. 다음은 속성 이름 및 유형의 정의입니다. 나는 그것이 한눈에 분명하다고 믿으며 소개되지 않을 것입니다.

<xsd:schema xmlns="http://www.back.com/schema/back-service"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
	xmlns:beans="http://www.springframework.org/schema/beans"
	targetNamespace="http://www.back.com/schema/back-service" 
		elementFormDefault="qualified" attributeFormDefault="unqualified">
	
	<xsd:import namespace="http://www.springframework.org/schema/beans"/>

	<xsd:element name="service">
	<xsd:complexType>
	<xsd:complexContent>
		<xsd:extension base="beans:identifiedType">
			<xsd:attribute name="interface" type="xsd:string" use="required"/>
			<xsd:attribute name="timeout" type="xsd:int" use="required"/>
			<xsd:attribute name="servicePort" type="xsd:int" use="required"/>
			<xsd:attribute name="ref" type="xsd:string" use="required"/>
			<xsd:attribute name="weight" type="xsd:int" use="optional"/>
			<xsd:attribute name="workerThreads" type="xsd:int" use="optional"/>
			<xsd:attribute name="appKey" type="xsd:string" use="required"/>
			<xsd:attribute name="groupName" type="xsd:string" use="optional"/>
		</xsd:extension>
	</xsd:complexContent>
	</xsd:complexType>
	</xsd:element>
</xsd:schema>

2. xsd를 작성한 후 새로운 Spring xml을 생성하고 커스텀 태그의 효과를 살펴 보자. xml의 ​​맨 위에 커스텀 주소와 xsd를 소개하고 동시에 로컬 xsd 파일에 주소를 바인딩해야합니다. Eclipse의 단계는 창-> 환경 설정-> XML-> XML CataLog-> 위치 추가 및 사용자 정의 xsd 경로 선택입니다. xsd 파일의 주소를 키에 넣으십시오. 예 : http://www.back.com/schema/back-service.xsd

<?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:backService="http://www.back.com/schema/back-service" 
    xmlns:backReference="http://www.back.com/schema/back-reference" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.back.com/schema/back-service 
        http://www.back.com/schema/back-service.xsd
        http://www.back.com/schema/back-reference
        http://www.back.com/schema/back-reference.xsd" >

	<bean id="serRemote" class="com.back.spring.test.RemoteServiceImpl" />
	<backService:service id="aaa" interface="com.back.spring.test.RemoteService" timeout="10"
	servicePort="9999" ref="serRemote" appKey="dodp" groupName="unps"/>

</beans>

셋째, 사용자 정의 레이블 확인을 설정하기 위해 BeanDefinitionParser를 확장하는 프로세스가 사용자 정의 Bean이됩니다.

1. NamespaceHandlerSupport 인터페이스가 확장되어 실제 구문 분석 된 클래스를 지정합니다. xsd 파일의 요소 이름에 따라 값은 확장 될 두 번째 실제 구문 분석 된 클래스입니다.

public class BackServiceNamespaceHandler extends NamespaceHandlerSupport{

	@Override
	public void init() {
		registerBeanDefinitionParser("service", new ProviderFactoryBeanDefinitionParser());
	}
}

2. AbstractSingleBeanDefinitionParser 확장. 사용자 정의 태그의 속성을 구문 분석합니다. 그런 다음 IOC에서 생성 한 개체에 속성을 삽입합니다.

public class ProviderFactoryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser{

	@Override
	protected Class<?> getBeanClass(Element element) {
		return ProviderFactoryBean.class;
	}
	
	@Override
	protected void doParse(Element element, BeanDefinitionBuilder builder) {
		try {
			String timeout = element.getAttribute("timeout");
			String serviceInterface = element.getAttribute("interface");
			String servicePort = element.getAttribute("servicePort");
			String ref = element.getAttribute("ref");
			String weight = element.getAttribute("weight");
			String workerThread = element.getAttribute("workerThread");
			String appKey = element.getAttribute("appKey");
			String groupName = element.getAttribute("groupName");
			
			builder.addPropertyValue("timeout", Integer.parseInt(timeout));
			builder.addPropertyValue("servicePort", Integer.parseInt(servicePort));
			builder.addPropertyValue("serviceInterface", Class.forName(serviceInterface));
			builder.addPropertyReference("serviceObject", ref);
			builder.addPropertyValue("appKey", appKey);
			if(NumberUtils.isNumber(weight)){
				builder.addPropertyValue("weight", Integer.parseInt(weight));
			}
			if(NumberUtils.isNumber(workerThread)){
				builder.addPropertyValue("workerThread", Integer.parseInt(workerThread));
			}
			if(StringUtils.isNotBlank(groupName)){
				builder.addPropertyValue("groupName", groupName);
			}
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
}

3. xsd 파일 구문 분석을 위해 두 개의 파일을 만들어야합니다. 기능은 스키마별로 로컬 파일을 지정하고 xsd로 해당 namespaceHandler 클래스를 지정하는 것입니다.

1) resources / META-INF의 새로운 파일 spring.handlers의 내용은 다음과 같습니다.

http\://www.back.com/schema/back-service=com.back.spring.provider.BackServiceNamespaceHandler

2) resources / META-INF 아래 새로 생성 된 spring.schemas 파일의 내용은 다음과 같습니다.

http\://www.back.com/schema/back-service.xsd=META-INF/back-service.xsd

 

좋아, 위의 작업을 수행하려면 실제로 필요한 클래스를 Dubbo와 같은 프레임 워크와 유사하게 Spring에 통합하는 것입니다. Spring 통합은 이러한 작업을 수행합니다. 개발자는 Spring에서 사용자 정의 태그 또는 사용자 정의 클래스 만 사용하면됩니다. 당신은 무엇을하길 원합니까.

마지막으로 위의 xml의 구성이 레지스트리에 등록하는 데 도움이되도록 빈에로드되었는지 테스트하는 테스트 클래스를 작성합니다 (레지스트리 코드는 이전 블로그에 있음).

public class TestSpringXsd {

	
	public static void main(String[] args) throws InterruptedException {
		
		ClassPathResource resource = new ClassPathResource("spring.xml");
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
		reader.loadBeanDefinitions(resource); 
		beanFactory.getBean("aaa");
		
		TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
	}
}

해당 주소의 사육사를 관찰하고 다음을 찾아 보자 : 인터페이스 주소 아래에 임시 노드 형태로 사육사에 ip와 포트가 등록되어있는 것을 확인

추천

출처blog.csdn.net/MrBack/article/details/105172907