RPC from zero (6) Many frameworks and Spring's secrets

Contents of this chapter:

1. The role of Spring FactoryBean and InitializingBean.

2. Customize the xsd file. Use tags to customize Spring xml files.

3. The process of extending BeanDefinitionParser to establish custom label resolution becomes our custom bean.

4. The post-operation of the custom bean completes the Netty service opening (described later), registry registration and other actions.

 

1. The role of Spring FactoryBean and InitializingBean.

The life cycle of Spring will be introduced when Spring is written separately later. Now only introduce the two interfaces of FactoryBean and InitializingBean.

1. InitializingBean. When we hand over the process of instantiating a class to the IOC container, we hope to do some operations after instantiating the class. You can implement this interface.

And write logic in the afterPropertiesSet() method.

2. FactoryBean. When we customize a class, we get another object and type in this class. You can use this interface. This is a bit abstract. For example, a specific scene: decorator class (decorator mode). We hope that there is a wrapper class outside the class that actually executes the logic to do something. You can use this interface to bind the decorated class (the current class itself) and the decorated class (the object obtained by getObject()). So as to do some logic.

Use these two features in Rpc, and put the opening of the Netty service and the registration of the registry in the post-action. Decoration class to decorate the corresponding implementation class of each interface.

/**
 * 
 * <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. Customize the xsd file. Use tags to customize Spring xml files.

1. The definition of xsd file. The file is placed in the resources/META-INF/ directory. For example, resources/META-INF/back-service.xsd

The address defined in xmlns: http://www.back.com/schema/back-service

You must pay attention to defining the name of the Element. When parsing, the corresponding parsing class will be found based on this name. Below is the definition of the attribute name and type. I believe it is clear at a glance and will not be introduced.

<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. Create a new Spring xml after writing xsd. Let's take a look at the effect of our custom tags. At the top of xml, we need to introduce our custom address and xsd. At the same time, bind the address to the local xsd file. The steps in eclipse are: window -> preferences -> XML -> XML CataLog -> Add Location and select our custom xsd path. Put the address of our xsd file in the key. Example: 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>

Third, the process of extending BeanDefinitionParser to establish custom label resolution becomes our custom bean.

1. The NamespaceHandlerSupport interface is extended to specify the real parsed class. According to the name of the Element in the xsd file as the key, the value is our second real parsed class to be extended

public class BackServiceNamespaceHandler extends NamespaceHandlerSupport{

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

2. AbstractSingleBeanDefinitionParser extension. Parse the attributes of custom tags. Then insert the attributes into the objects created by the 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. Two files must be created for xsd file parsing. The function is to specify the local file by schema and the corresponding namespaceHandler class by xsd

1) The content of the new file spring.handlers under resources/META-INF is as follows

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

2) The content of the newly created file spring.schemas under resources/META-INF is as follows

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

 

Ok, to do the above is actually to integrate the classes we need into Spring, similar to the frameworks such as Dubbo, the integration of Spring is doing these things, developers only need to use custom tags or custom classes in Spring , You can accomplish what you want to do.

Finally, we write a test class to test whether the configuration in the above xml is loaded into a bean to help us register with the registry (the registry code is in the previous blog).

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);
	}
}

Let's observe the zookeeper of the corresponding address and find the following: It is found that the ip and port have been registered to zookeeper in the form of temporary nodes under the interface address

Guess you like

Origin blog.csdn.net/MrBack/article/details/105172907