1.接口 Class<?> resourceClass

2.获取builder

BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(resourceClass);

3.获取接口对应的动态代理class

Class<?> targetProxyClass = Proxy.getProxyClass(XXX.class.getClassLoader(), new Class[]{resourceClass});

4.targetProxyClass构造参数类型 InvocationHandler,通过builder设置

builder.addConstructorArgValue(Proxy.getInvocationHandler(xxxProxyBean) 或者 new InvocationHandler(){...});

 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

beanDefinition.setBeanClass(targetProxyClass);

registry.registerBeanDefinition("beanName", beanDefinition);

5.记录一下自己曾经写的一个例子

5.1 抽象类ProxyFactoryBean

package com.hjzgg.apigateway.soa.proxy;import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.consumer.ConsumerProxyFactoryBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.ClassUtils;import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** Created by hujunzheng on 2017/7/7.*/
public abstract class ProxyFactoryBean implements FactoryBean {protected Class<?> selfDynamicProxyClass;//代理类protected Class<?> resourceClass;//接口类protected String version;//dubbo 版本protected String group;//dubbo 分组protected Object proxy;//代理对象protected Method createProxyMethod;public ProxyFactoryBean(Class<?> selfDynamicProxyClass, Class<?> resourceClass, String version, String group) throws SoaException {if (Objects.isNull(selfDynamicProxyClass)) {throw new SoaException("selfDynamicProxyClass 动态代理类不能为null");}try {this.createProxyMethod = Stream.of(selfDynamicProxyClass.getMethods()).filter(method -> Modifier.isStatic(method.getModifiers())&& Modifier.isPublic(method.getModifiers())&& !Modifier.isAbstract(method.getModifiers())&& method.getParameters().length == 2&& method.getParameters()[0].getType().equals(ProxyFactoryBean.class)&& method.getParameters()[1].getType().equals(Class.class)&& !method.getReturnType().equals(void.class)).collect(Collectors.toList()).get(0);} catch (Exception e) {throw new SoaException("500", String.format("%s %s %s和%s %s, %s %s", ClassUtils.getQualifiedName(selfDynamicProxyClass), " 没有参数类型是 ", ClassUtils.getQualifiedName(ConsumerProxyFactoryBean.class), ClassUtils.getQualifiedName(Class.class), " 的、公共的、非抽象的、返回值非void的方法", "请将你的动态代理类继承", ClassUtils.getQualifiedName(DynamicProxyAdapter.class)), e);}this.selfDynamicProxyClass = selfDynamicProxyClass;this.resourceClass = resourceClass;this.version = version;this.group = group;}protected Object newInstance() throws SoaException {if(this.isSingleton() && this.proxy != null) {return proxy;}synchronized (this) {Object target;try {target = this.createProxyMethod.invoke(null,this, selfDynamicProxyClass);} catch (Exception e) {throw new SoaException("500", String.format("%s %s %s", ClassUtils.getQualifiedName(selfDynamicProxyClass), createProxyMethod.getName(), "创建代理类异常"), e);}if(proxy == null) {proxy = target;}return target;}}public Class<?> getSelfDynamicProxyClass() {return selfDynamicProxyClass;}public void setSelfDynamicProxyClass(Class<?> selfDynamicProxyClass) {this.selfDynamicProxyClass = selfDynamicProxyClass;}public Class<?> getResourceClass() {return resourceClass;}public void setResourceClass(Class<?> resourceClass) {this.resourceClass = resourceClass;}public String getVersion() {return version;}public void setVersion(String version) {this.version = version;}public String getGroup() {return group;}public void setGroup(String group) {this.group = group;}
}

5.2 ProxyFactoryBean具体实现类ProviderProxyFactoryBean

package com.hjzgg.apigateway.soa.proxy.provider;import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.ProxyFactoryBean;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetClassAware;import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author hujunzheng* @create 2018-02-18 下午3:01**/
public class ProviderProxyFactoryBean extends ProxyFactoryBean {public ProviderProxyFactoryBean(Class<?> selfDynamicProxyClass, Class<?> resourceClass, String version, String group) throws SoaException {super(selfDynamicProxyClass, resourceClass, version, group);}@Overridepublic Object getObject() throws Exception {return this.newInstance();}@Overridepublic Class<?> getObjectType() {return resourceClass;}@Overridepublic boolean isSingleton() {return true;}public static Class<?> getProxyClass(Class<?> resourceClass) {/*** @see com.hjzgg.apigateway.dubbo.configure.SelfDubboAnnotationBean#postProcessAfterInitialization(Object, String)* @see org.springframework.aop.support.AopUtils#isAopProxy(Object)* @see org.springframework.aop.support.AopUtils#getTargetClass(Object)* @see com.hjzgg.apigateway.soa.proxy.provider.ProviderDynamicProxy#invoke(Object, Method, Object[])* */return Proxy.getProxyClass(ProviderProxyFactoryBean.class.getClassLoader(), new Class[]{resourceClass, SpringProxy.class, TargetClassAware.class});}
}

5.3 动态代理适配器DynamicProxyAdapter

package com.hjzgg.apigateway.soa.proxy;import com.hjzgg.apigateway.soa.exceptions.SoaException;
import org.springframework.util.ClassUtils;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @author hujunzheng* @create 2018-02-04 上午12:00**/
public class DynamicProxyAdapter implements InvocationHandler {public DynamicProxyAdapter(ProxyFactoryBean factoryBean) {this.bean = factoryBean;}protected ProxyFactoryBean bean;@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {throw new SoaException(String.format("%s %s %s", "你应当重写", ClassUtils.getQualifiedName(DynamicProxyAdapter.class), "invoke方法"));}public static Object createJDKProxy(ProxyFactoryBean factoryBean, Class<?> selfDynamicProxyClass) throws SoaException {if (!DynamicProxyAdapter.class.equals(selfDynamicProxyClass.getSuperclass())) {throw new SoaException(String.format("%s %s %s", ClassUtils.getQualifiedName(selfDynamicProxyClass), "需要继承", ClassUtils.getQualifiedName(DynamicProxyAdapter.class)));}Object selfDynamicProxyInstance;try {selfDynamicProxyInstance = selfDynamicProxyClass.getConstructor(factoryBean.getClass()).newInstance(factoryBean);} catch (Exception e) {throw new SoaException("500", "动态代理类创建失败", e);}Object proxy = Proxy.newProxyInstance(selfDynamicProxyClass.getClassLoader(),new Class[]{factoryBean.getResourceClass()}, (InvocationHandler) selfDynamicProxyInstance);return proxy;}
}

5.4 继承DynamicProxyAdapter 实现invoke接口 ProviderDynamicProxy

package com.hjzgg.apigateway.soa.proxy.provider;import com.hjzgg.apigateway.commons.utils.ContextUtils;
import com.hjzgg.apigateway.soa.annotation.SOAImplements;
import com.hjzgg.apigateway.soa.exceptions.SoaException;
import com.hjzgg.apigateway.soa.proxy.DynamicProxyAdapter;
import com.hjzgg.apigateway.soa.proxy.consumer.ConsumerProxyFactoryBean;
import org.springframework.aop.TargetClassAware;
import org.springframework.util.ClassUtils;import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;public class ProviderDynamicProxy extends DynamicProxyAdapter {private static final ConcurrentHashMap<Class<?>, Object> map = new ConcurrentHashMap<>();public ProviderDynamicProxy(ProviderProxyFactoryBean factoryBean) {super(factoryBean);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (method.equals(TargetClassAware.class.getMethod("getTargetClass", new Class[]{}))) {return bean.getResourceClass();}return method.invoke(this.findRelevantServiceProvider(), args);} catch (Exception e) {throw new SoaException("500", String.format("%s %s %s", "invoke service proxy object error!", ClassUtils.getQualifiedName(this.bean.getResourceClass()), method.getName()), e);}}private Object findRelevantServiceProvider() throws SoaException {Class<?> resourceClass = super.bean.getResourceClass();if (!map.contains(resourceClass)) {Stream<?> stream = ContextUtils.getBeans(SOAImplements.class).stream().filter(serviceProvider -> resourceClass.isAssignableFrom(serviceProvider.getClass()));if (stream.count() > 1) {throw new SoaException(String.format("multiple relevant service provider found with annotation %s and interface is %s", ClassUtils.getQualifiedName(SOAImplements.class), ClassUtils.getQualifiedName(resourceClass)));}if (stream.count() == 1) {map.put(resourceClass, stream.findFirst().get());} else {List<?> objects = ContextUtils.getBeans(SOAImplements.class);if (objects.size() > 1) {throw new SoaException(String.format("multiple relevant service provider found with annotation %s", ClassUtils.getQualifiedName(SOAImplements.class)));}if (objects.size() == 1) {map.put(resourceClass, objects.get(0));} else {try {Object object = ContextUtils.getBean(resourceClass);map.put(resourceClass, object);} catch (Exception e) {throw new SoaException("500", String.format("find relevant service provider with interface %s error", ClassUtils.getQualifiedName(resourceClass)), e);}}}}return map.get(resourceClass);}
}

5.5 注册类型是jdk proxy类型的bean

//参数dynamicProxyClass 是 ProviderDynamicProxy
public static boolean registerProvider(BeanDefinitionRegistry registry, Class<?> dynamicProxyClass, Class<?> resourceClass) {String apiClassInfo = ClassUtils.getQualifiedName(resourceClass);try {/*** 通过代理bean的方式创建创建 服务bean* @see com.hjzgg.apigateway.dubbo.configure.SelfDubboAnnotationBean#postProcessAfterInitialization(Object, String)* if (AopUtils.isAopProxy(bean)), 判断bean的类型如果是代理类型,进行dubbo注解解析处理* */BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(resourceClass);String dubboVersion = resourceClass.getAnnotation(Service.class).version();String dubboGroup = resourceClass.getAnnotation(Service.class).group();ProviderProxyFactoryBean providerProxyFactoryBean = new ProviderProxyFactoryBean(dynamicProxyClass, resourceClass, dubboVersion, dubboGroup);/*** providerProxyFactoryBean.getObject() 得到的是通过 Proxy.newInstance方法获取到的代理类* @see com.hjzgg.apigateway.soa.proxy.DynamicProxyAdapter#createJDKProxy(ProxyFactoryBean, Class)* 可通过 Proxy.getInvocationHandler方法拿到 InvocationHandler实例*/Class<?> targetProxyClass = ProviderProxyFactoryBean.getProxyClass(resourceClass);builder.addConstructorArgValue(Proxy.getInvocationHandler(providerProxyFactoryBean.getObject()));AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();beanDefinition.setBeanClass(targetProxyClass);beanDefinition.setAttribute(Constants.API_CLASS_INFO, resourceClass);String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);if (registry.containsBeanDefinition(beanName)) {log.debug(beanName + " already exists! Class is " + apiClassInfo + " .");return false;}registry.registerBeanDefinition(beanName, beanDefinition);return true;} catch (Exception e) {log.error("registerProvider proxy bean error! Class is " + apiClassInfo + " .");return false;}
}

5.6 附加SelfDubboAnnotationBean

package com.hjzgg.apigateway.dubbo.configure;import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ConcurrentHashSet;
import com.alibaba.dubbo.config.*;
import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.config.spring.ServiceBean;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;/*** @see com.alibaba.dubbo.config.spring.AnnotationBean*/
public class SelfDubboAnnotationBean extends AbstractConfig implements DisposableBean, BeanPostProcessor, ApplicationContextAware, Serializable {private static final Logger logger = LoggerFactory.getLogger(Logger.class);private String annotationPackage;private String[] annotationPackages;private final Set<ServiceConfig<?>> serviceConfigs = new ConcurrentHashSet<>();private final ConcurrentMap<String, ReferenceBean<?>> referenceConfigs = new ConcurrentHashMap<>();public String getPackage() {return annotationPackage;}public void setPackage(String annotationPackage) {this.annotationPackage = annotationPackage;this.annotationPackages = (annotationPackage == null || annotationPackage.length() == 0) ? null: Constants.COMMA_SPLIT_PATTERN.split(annotationPackage);}private ApplicationContext applicationContext;public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public void destroy() throws Exception {for (ServiceConfig<?> serviceConfig : serviceConfigs) {try {serviceConfig.unexport();} catch (Throwable e) {logger.error(e.getMessage(), e);}}for (ReferenceConfig<?> referenceConfig : referenceConfigs.values()) {try {referenceConfig.destroy();} catch (Throwable e) {logger.error(e.getMessage(), e);}}}public Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {if (! isMatchPackage(bean)) {return bean;}if (AopUtils.isAopProxy(bean)) {/*** @see com.hjzgg.apigateway.soa.executor.RegisterBeanUtils#registerProvider* @see com.hjzgg.apigateway.soa.proxy.provider.ProviderDynamicProxy#invoke* *///获取被代理的真实类或者接口类Class<?> targetClass = AopUtils.getTargetClass(bean);Service service = targetClass.getAnnotation(Service.class);if (service != null) {ServiceBean<Object> serviceConfig = new ServiceBean<Object>(service);if (void.class.equals(service.interfaceClass())&& "".equals(service.interfaceName())) {if (!(targetClass.isInterface() || targetClass.getInterfaces().length > 0)) {throw new IllegalStateException("Failed to export remote service class " + bean.getClass().getName() + ", cause: The @Service undefined interfaceClass or interfaceName, and the service class unimplemented any interfaces.");} else {if (targetClass.isInterface()) {serviceConfig.setInterface(targetClass);}if (targetClass.getInterfaces().length > 0) {serviceConfig.setInterface(targetClass.getInterfaces()[0]);}}}if (applicationContext != null) {serviceConfig.setApplicationContext(applicationContext);if (service.registry() != null && service.registry().length > 0) {List<RegistryConfig> registryConfigs = new ArrayList<RegistryConfig>();for (String registryId : service.registry()) {if (registryId != null && registryId.length() > 0) {registryConfigs.add(applicationContext.getBean(registryId, RegistryConfig.class));}}serviceConfig.setRegistries(registryConfigs);}if (service.provider() != null && service.provider().length() > 0) {serviceConfig.setProvider(applicationContext.getBean(service.provider(),ProviderConfig.class));}if (service.monitor() != null && service.monitor().length() > 0) {serviceConfig.setMonitor(applicationContext.getBean(service.monitor(), MonitorConfig.class));}if (service.application() != null && service.application().length() > 0) {serviceConfig.setApplication(applicationContext.getBean(service.application(), ApplicationConfig.class));}if (service.module() != null && service.module().length() > 0) {serviceConfig.setModule(applicationContext.getBean(service.module(), ModuleConfig.class));}if (service.provider() != null && service.provider().length() > 0) {serviceConfig.setProvider(applicationContext.getBean(service.provider(), ProviderConfig.class));}if (service.protocol() != null && service.protocol().length > 0) {List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>();for (String protocolId : service.registry()) {if (protocolId != null && protocolId.length() > 0) {protocolConfigs.add(applicationContext.getBean(protocolId, ProtocolConfig.class));}}serviceConfig.setProtocols(protocolConfigs);}try {serviceConfig.afterPropertiesSet();} catch (RuntimeException e) {throw e;} catch (Exception e) {throw new IllegalStateException(e.getMessage(), e);}}serviceConfig.setRef(bean);serviceConfigs.add(serviceConfig);serviceConfig.export();}}return bean;}public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {Service service = (AopUtils.isAopProxy(bean) && !Objects.isNull(AopUtils.getTargetClass(bean).getAnnotation(Service.class)))? AopUtils.getTargetClass(bean).getAnnotation(Service.class): bean.getClass().getAnnotation(Service.class);if (Objects.isNull(service)) {return bean;}try {InvocationHandler h = Proxy.getInvocationHandler(service);// 获取 AnnotationInvocationHandler 的 memberValues 字段Field memberValuesField = h.getClass().getDeclaredField("memberValues");// 因为这个字段事 private final 修饰,所以要打开权限memberValuesField.setAccessible(true);// 获取 memberValuesMap memberValues = (Map) memberValuesField.get(h);Service serviceInstance = Stream.of(bean.getClass().getInterfaces()).filter(iface -> iface.getAnnotation(Service.class) != null).collect(Collectors.toList()).get(0).getAnnotation(Service.class);memberValues.put("version", serviceInstance.version());memberValues.put("group", serviceInstance.group());} catch (Exception e) {throw new BeanCreationException(String.format("%s %s %s %s %s", "修改", ClassUtils.getQualifiedName(bean.getClass()), "的注解", ClassUtils.getQualifiedName(Service.class), "的 group值和version值出错"), e);}return bean;}private boolean isMatchPackage(Object bean) {if (annotationPackages == null || annotationPackages.length == 0) {return true;}String beanClassName = bean.getClass().getName();for (String pkg : annotationPackages) {if (beanClassName.startsWith(pkg)) {return true;}}return false;}}

View Code

5.7 附加AopUtils相关方法

/*** Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.* <p>This method additionally checks if the given object is an instance* of {@link SpringProxy}.* @param object the object to check* @see #isJdkDynamicProxy* @see #isCglibProxy*/
public static boolean isAopProxy(Object object) {return (object instanceof SpringProxy &&(Proxy.isProxyClass(object.getClass()) || ClassUtils.isCglibProxyClass(object.getClass())));
}/*** Determine the target class of the given bean instance which might be an AOP proxy.* <p>Returns the target class for an AOP proxy or the plain class otherwise.* @param candidate the instance to check (might be an AOP proxy)* @return the target class (or the plain class of the given object as fallback;* never {@code null})* @see org.springframework.aop.TargetClassAware#getTargetClass()* @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)*/
public static Class<?> getTargetClass(Object candidate) {Assert.notNull(candidate, "Candidate object must not be null");Class<?> result = null;if (candidate instanceof TargetClassAware) {result = ((TargetClassAware) candidate).getTargetClass();}if (result == null) {result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());}return result;
}

View Code

转载于:https://www.cnblogs.com/hujunzheng/p/8527338.html

spring AbstractBeanDefinition创建bean类型是动态代理类的方式相关推荐

  1. 【Spring】AOP底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂加工原始对象

    一.AOP概念 AOP (Aspect Oriented Programing) 面向切面编程 = Spring动态代理开发 以切面为基本单位的程序开发,通过切面间的彼此协同,相互调用,完成程序的构建 ...

  2. 【Spring AOP】AOP 底层实现原理 —— 动态代理类的创建(JDK、CGlib)、工厂如何加工原始对象

    AOP编程 AOP 编程 AOP 概念 AOP 编程的开发步骤 切面的名词解释 AOP 的底层实现原理 动态代理类的创建 JDK 的动态代理(原理 + 编码) CGlib 的动态代理 Spring 工 ...

  3. Spring 从入门到精通 (十六) AOP底层如何创建动态代理类

    关键词:Spring | AOP | 创建代理类 | 底层 本专栏通过理论和实践相结合,系统学习框架核心思想及简单原理,原创不易,如果觉得文章对你有帮助,点赞收藏支持博主 ✨ 目录 一.创建对象三要素 ...

  4. Spring AOP源码解析——AOP动态代理原理和实现方式

    2019独角兽企业重金招聘Python工程师标准>>> Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和 ...

  5. Spring AOP底层实现原理(动态代理)

    什么是AOP? AOP(面向切面编程)通过预编译的方式 和 运行期动态代理的方式来实现程序功能统一维护的一种方式,是OOP(面向对象编程)的延续.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业 ...

  6. Spring注解创建Bean的几种方式

    Spring注解创建Bean的几种方式 1.@Component系列 @Component @Service @Repository @Controller @Configuration 2. 依附于 ...

  7. Spring 容器AOP的实现原理——动态代理

    本文来自极客学院 Spring 容器AOP的实现原理--动态代理 之前写了一篇关于IOC的博客--<Spring容器IOC解析及简单实现>,今天再来聊聊AOP.大家都知道Spring的两大 ...

  8. spring框架中JDK和CGLIB动态代理区别

    转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...

  9. Java动态代理类使用

    Java动态代理类使用 Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类: 一.Interface InvocationHandler:该接口中仅定义了一个方法O ...

最新文章

  1. SSO单点登录三种情况的实现方式详解
  2. 高孟平:深度学习是视频技术与人眼视觉连结的重要桥梁
  3. pc网站和移动网站在同一服务器吗,机动都市阿尔法PC服和移动服互通吗
  4. 树状数组 Binary Indexed Tree/Fenwick Tree
  5. oracle 的用户是什么,User 用户 还是 Role 角色 - Oracle 的 Public 是什么?
  6. 重磅!Intel联合OpenStack基金会发布Kata Container项目
  7. 职业生涯(一)——你就是自己想要成为的那个人!
  8. 用UltraISO制作CentOS的DVD光盘启动盘 安装系统
  9. 28款数据恢复软件对比测试
  10. python编程语言的缺点-多种编程语言的优缺点梳理
  11. 健身房有哪些令人讨厌的行为?
  12. mappedBy和JoinColumn实质上指向的是同一个表即外键作为主键所在的表对应的实体
  13. CC00416.CloudKubernetes——|KuberNetesNetworkPolicy.V08|——|NetworkPolicy.v08|隔离中间件服务.v04|
  14. 别轻易自责,专注力和自制力是稀缺资源
  15. 37互娱,2019秋招提前批,web后端工程师
  16. QDUOJ 点击此处签到(并查集)
  17. 19.3 C++STL标准模板库大局观-容器的说明和简单应用例续
  18. nginx配置wss协议
  19. Mysql主键与事务
  20. mac安装windows虚拟机并且进行远程连接

热门文章

  1. 怎么测试服务器的性能,如何测试服务器性能
  2. pdo mysql 和 mysqli_PHP中MySQL、MySQLi和PDO的用法和区别
  3. Php中跳转语句goto,phpgoto语句
  4. Jmeter常用插件——梯度加压、响应时间、TPS_老版本
  5. Jenkins操作手册
  6. 正则表达式中的开头和结尾
  7. Error querying database. Cause: java.lang.IllegalArgumentException:Failed to decrypt. 错误解决方案
  8. maven打包时跳过测试
  9. 软件设计师 - 软件工程
  10. JavaScript-严格检查模式