欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

spring boot 动态生成接口实现类的场景分析

程序员文章站 2022-04-06 09:09:29
目录一: 定义注解二: 建立动态代理类三: 注入spring容器四: 编写拦截器五: 新建测试类在某些业务场景中,我们只需要业务代码中定义相应的接口或者相应的注解,并不需要实现对应的逻辑。比如 myb...

在某些业务场景中,我们只需要业务代码中定义相应的接口或者相应的注解,并不需要实现对应的逻辑。

比如 mybatis和feign: 在 mybatis 中,我们只需要定义对应的mapper接口;在 feign 中,我们只需要定义对应业务系统中的接口即可。

那么在这种场景下,具体的业务逻辑时怎么执行的呢,其实原理都是动态代理。

我们这里不具体介绍动态代理,主要看一下它在springboot项目中的实际应用,下面我们模仿feign来实现一个调用三方接口的 httpclient。

一: 定义注解

package com.mysgk.blogdemo.annotation;

public @interface myhttpclient {
}

二: 建立动态代理类

package com.mysgk.blogdemo.proxy;

import org.springframework.beans.factory.factorybean;

import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;

public class ribbonaopproxyfactory<t> implements factorybean<t>, invocationhandler {

	private class<t> interfaceclass;

	public class<t> getinterfaceclass() {
		return interfaceclass;
	}

	public void setinterfaceclass(class<t> interfaceclass) {
		this.interfaceclass = interfaceclass;
	}

	@override
	public t getobject() throws exception {
		return (t) proxy.newproxyinstance(this.getclass().getclassloader(), new class[]{interfaceclass}, this);
	}

	@override
	public class<?> getobjecttype() {
		return interfaceclass;
	}

	@override
	public boolean issingleton() {
		return true;
	}

	/**
	 真正执行的方法
	 */
	@override
	public object invoke(object proxy, method method, object[] args) throws throwable {
		return "invoke " + proxy.getclass().getname() + "." + method.getname() + " , do anything ..";
	}
}

三: 注入spring容器

package com.mysgk.blogdemo.start;

import cn.hutool.core.util.classutil;
import cn.hutool.core.util.strutil;
import com.mysgk.blogdemo.annotation.myhttpclient;
import com.mysgk.blogdemo.proxy.ribbonaopproxyfactory;
import org.slf4j.logger;
import org.slf4j.loggerfactory;
import org.springframework.beans.beansexception;
import org.springframework.beans.factory.config.configurablelistablebeanfactory;
import org.springframework.beans.factory.support.beandefinitionbuilder;
import org.springframework.beans.factory.support.beandefinitionregistry;
import org.springframework.beans.factory.support.beandefinitionregistrypostprocessor;
import org.springframework.beans.factory.support.genericbeandefinition;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.stereotype.component;

import java.util.set;

@component
public class scanhttpclients implements beandefinitionregistrypostprocessor, applicationcontextaware {

	private final logger logger = loggerfactory.getlogger(scanhttpclients.class);

	private applicationcontext ctx;

	public void run(beandefinitionregistry registry) {

		set<class<?>> scanpackage = classutil.scanpackagebyannotation("com.mysgk", myhttpclient.class);

		for (class<?> cls : scanpackage) {

			beandefinitionbuilder builder = beandefinitionbuilder.genericbeandefinition(cls);
			genericbeandefinition definition = (genericbeandefinition) builder.getrawbeandefinition();
			definition.getpropertyvalues().add("interfaceclass", definition.getbeanclassname());
			definition.setbeanclass(ribbonaopproxyfactory.class);
			definition.setautowiremode(genericbeandefinition.autowire_by_type);
			string beanname = strutil.removepreandlowerfirst(cls.getsimplename(), 0) + "ribbonclient";
			registry.registerbeandefinition(beanname, definition);
		}

	}

	@override
	public void postprocessbeandefinitionregistry(beandefinitionregistry registry) throws beansexception {
		run(registry);
	}

	@override
	public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) throws beansexception {

	}

	@override
	public void setapplicationcontext(applicationcontext applicationcontext) throws beansexception {
		this.ctx = ctx;
	}


}

四: 编写拦截器

package com.mysgk.blogdemo.aop;

import org.aspectj.lang.proceedingjoinpoint;
import org.aspectj.lang.annotation.around;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.pointcut;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.httpentity;
import org.springframework.http.httpmethod;
import org.springframework.http.responseentity;
import org.springframework.stereotype.component;
import org.springframework.web.client.resttemplate;
@component
@aspect
public class interceptannotation {

	@autowired
	private resttemplate ribbonloadbalanced;

	@pointcut("@annotation(com.mysgk.blogdemo.annotation.myhttpclient)")
	public void execute() {

	}

	@around("execute()")
	public object interceptannotation(proceedingjoinpoint joinpoint) throws throwable {
		/**
		 * 此处省略 获取 url, httpmethod, requestentity, responsetype 等参数的处理过程
		 */
		responseentity<?> exchange = ribbonloadbalanced.exchange("url", httpmethod.get, httpentity.empty, object.class);
		return exchange.getbody();
	}

}

五: 新建测试类

package com.mysgk.blogdemo.client;

import com.mysgk.blogdemo.annotation.myhttpclient;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestbody;

@myhttpclient
public interface myhttpclienttest {

	@postmapping(value = "test/t1")
	object test(string param);

}

项目结构:

spring boot 动态生成接口实现类的场景分析

到此这篇关于spring boot 动态生成接口实现类的文章就介绍到这了,更多相关spring boot 接口实现类内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!