Spring Aop 中的 IntroductionInfo, IntroductionAdvisor

/**
 * Interface supplying the information necessary to describe an introduction.
 * 为描述一个introduction(引入)提供必要信息的接口。但是这个接口之定义了一个
 * Class<?>[] getInterfaces()方法,看来 introduction 最主要的信息就是要引入的接口
 * 
 * <p>{@link IntroductionAdvisor IntroductionAdvisors} must implement this
 * interface. If an {@link org.aopalliance.aop.Advice} implements this,
 * it may be used as an introduction without an {@link IntroductionAdvisor}.
 * In this case, the advice is self-describing, providing not only the
 * necessary behavior, but describing the interfaces it introduces.
 * IntroductionAdvisor 必须实现这个接口,假如一个 Advice 实现了IntroductionInfo,
 * 它就可以被当作一个没有 IntroductionAdvisor 的introduction来使用。在这种情况下
 * 这个Advice是自我描述的,不仅提供了必要的行为,和描述了要引入的接口
 * 
 * @author Rod Johnson
 * @since 1.1.1
 */
public interface IntroductionInfo {

	/**
	 * 返回这个Advisor 或者 Advice 引入的额外的接口
	 * 这里的额外接口指的是,Advisor和Advice 没有实现这些接口,但是要具有这些接口的能力
	 * Return the additional interfaces introduced by this Advisor or Advice.
	 * @return the introduced interfaces
	 */
	Class<?>[] getInterfaces();

}
/**
 * Superinterface for advisors that perform one or more AOP <b>introductions</b>.
 * 
 * 
 * <p>This interface cannot be implemented directly; subinterfaces must
 * provide the advice type implementing the introduction.
 *
 * <p>Introduction is the implementation of additional interfaces
 * (not implemented by a target) via AOP advice.
 * 引入是target对象通过Aop实现的额外的接口,这些额外的接口指的是target没有
 * 实现的一些接口 
 * 比如:target 实现了接口A 和 接口B,但是还想给 target 添加接口C 和 接口D 的功能,
 * 接口C 和 接口D 就属于引入的接口
 * @author Rod Johnson
 * @since 04.04.2003
 * @see IntroductionInterceptor
 */
public interface IntroductionAdvisor extends Advisor, IntroductionInfo {

	/**
	 * Return the filter determining which target classes this introduction
	 * should apply to.
	 * 返回一个过滤器,这个过滤器用来决定这个 introduction 因该引用到哪些类上
	 * 
	 * <p>This represents the class part of a pointcut. Note that method
	 * matching doesn't make sense to introductions.
	 * 这代表了切点的 class 部分。注意对于introduction来说,方法匹配不起作用
	 * 
	 * @return the class filter
	 */
	ClassFilter getClassFilter();

	/**
	 * Can the advised interfaces be implemented by the introduction advice?
	 * Invoked before adding an IntroductionAdvisor.
	 * 在IntroductionAdvisor被添加之前调用,用来校验 introduction 引入的接口
	 * 能不能被introduction advice实现
	 * @throws IllegalArgumentException if the advised interfaces can't be
	 * implemented by the introduction advice
	 * 
	 */
	void validateInterfaces() throws IllegalArgumentException;

}
/**
 * Simple {@link org.springframework.aop.IntroductionAdvisor} implementation
 * that by default applies to any class.
 * 
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 11.11.2003
 */
@SuppressWarnings("serial")
public class DefaultIntroductionAdvisor implements IntroductionAdvisor, ClassFilter, Ordered, Serializable {

	private final Advice advice;

	private final Set<Class<?>> interfaces = new LinkedHashSet<>();

	private int order = Ordered.LOWEST_PRECEDENCE;


	/**
	 * Create a DefaultIntroductionAdvisor for the given advice.
	 * @param advice the Advice to apply (may implement the
	 * {@link org.springframework.aop.IntroductionInfo} interface)
	 * @see #addInterface
	 */
	public DefaultIntroductionAdvisor(Advice advice) {
		// 这里的Advice同时也实现了IntroductionInfo,说明这个Advice实例既提供了要引入的接口
        // ,又具有根据本次请求的Method的,将请求转发到delegate的能力
        // 比如说:DelegatingIntroductionInterceptor
		this(advice, (advice instanceof IntroductionInfo ? (IntroductionInfo) advice : null));
	}

	/**
	 * Create a DefaultIntroductionAdvisor for the given advice.
	 * @param advice the Advice to apply
	 * @param introductionInfo the IntroductionInfo that describes
	 * the interface to introduce (may be {@code null})
	 */
	public DefaultIntroductionAdvisor(Advice advice, @Nullable IntroductionInfo introductionInfo) {
		Assert.notNull(advice, "Advice must not be null");
        // 这里传进来的 Advice 不是像PointcutAdvisor中的Advice那样,对目标对象的方法进行加强
		// 主要的业务还是在代理的目标对象
		// DefaultIntroductionAdvisor的Advice最终是要完成主要业务的,Advice持有能够解决
        // 所引入的接口的问题的实例 Object delegate ,这个delegate本身实现了引入的接口,
        // 当执行到执行链中的Introduction Advice时,这个Advice会先判断这次调用的Method方法
        // 所属的Class是不是Introduction引入的接口,如果是就直接把这个调用准发到 delegate
        // ,delegate实现了Introduction引入的接口,能够解决本次调用,解决完了,直接就返回了
        // 不再将请求向后传递了
		this.advice = advice;
		if (introductionInfo != null) {
			Class<?>[] introducedInterfaces = introductionInfo.getInterfaces();
			if (introducedInterfaces.length == 0) {
				throw new IllegalArgumentException(
						"IntroductionInfo defines no interfaces to introduce: " + introductionInfo);
			}
			for (Class<?> ifc : introducedInterfaces) {
				addInterface(ifc);
			}
		}
	}

	/**
	 * Create a DefaultIntroductionAdvisor for the given advice.
	 * @param advice the Advice to apply
	 * @param ifc the interface to introduce
	 */
	public DefaultIntroductionAdvisor(DynamicIntroductionAdvice advice, Class<?> ifc) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
		addInterface(ifc);
	}


	/**
	 * Add the specified interface to the list of interfaces to introduce.
	 * 添加要引入的接口
	 * @param ifc the interface to introduce
	 */
	public void addInterface(Class<?> ifc) {
		Assert.notNull(ifc, "Interface must not be null");
		if (!ifc.isInterface()) {
			throw new IllegalArgumentException("Specified class [" + ifc.getName() + "] must be an interface");
		}
		this.interfaces.add(ifc);
	}

    // 这里相当于实现了 IntroductionInfo 的public Class<?>[] getInterfaces();
    // 当通过AdvisedSupport#addAdvisor(int,org.springframework.aop.Advisor)
    // 方法添加 Advisor 的时候,判断如果添加的Advisor,是一个IntroductionAdvisor
    // ,就会将调用IntroductionAdvisor.getInterfaces()获取所有引入的接口,添加到
    // AdvisedSupport.interfaces中,AdvisedSupport.interfaces中放的都是生成的代理
    // 对象需要实现的接口,之后实现了这些接口,后期生成的代理才能强转为这些接口进行调用
	@Override
	public Class<?>[] getInterfaces() {
		return ClassUtils.toClassArray(this.interfaces);
	}

	@Override
	public void validateInterfaces() throws IllegalArgumentException {
		for (Class<?> ifc : this.interfaces) {
			if (this.advice instanceof DynamicIntroductionAdvice &&
					!((DynamicIntroductionAdvice) this.advice).implementsInterface(ifc)) {
				throw new IllegalArgumentException("DynamicIntroductionAdvice [" + this.advice + "] " +
						"does not implement interface [" + ifc.getName() + "] specified for introduction");
			}
		}
	}


	@Override
	public Advice getAdvice() {
		return this.advice;
	}

	@Override
	public boolean isPerInstance() {
		return true;
	}

	@Override
	public ClassFilter getClassFilter() {
		// 因为DefaultIntroductionAdvisor本来就实现了ClassFilter
		// 返回this
		return this;
	}

	@Override
	public boolean matches(Class<?> clazz) {
		// 因为DefaultIntroductionAdvisor实现了ClassFilter
		// 所以必须实现 matches 方法,这里直接返回 true
		// 表示所有的 Class 都能匹配成功
		return true;
	}

}

上面说了创建 DefaultIntroductionAdvisor 的时候,需要一个能根据本次调用的Method的,将调用转发到 delegate 的Advice,DelegatingIntroductionInterceptor 就是这样一个Advice,DelegatingIntroductionInterceptor通过继承IntroductionInfoSupport具有了校验一个Method是否属于被引入的某一个接口的能力,当然IntroductionInfoSupport校验是所用的接口数据也是DelegatingIntroductionInterceptor 通过 implementInterfacesOnObject(delegate) 传给它的

/**
 * Convenient implementation of the
 * {@link org.springframework.aop.IntroductionInterceptor} interface.
 *
 * <p>Subclasses merely need to extend this class and implement the interfaces
 * to be introduced themselves. In this case the delegate is the subclass
 * instance itself. Alternatively a separate delegate may implement the
 * interface, and be set via the delegate bean property.
 * 很少需要扩展这个类,并且子类实现要引入的所有接口,如果真是这种情况,子类自己就是delegate。
 * 还有可选方案就是,用一个单独的 delegate 实现要引入的所有接口,然后通过构造方法或者setter
 * 将单独的 delegate 设置给 delegate 属性
 * <p>Delegates or subclasses may implement any number of interfaces.
 * All interfaces except IntroductionInterceptor are picked up from
 * the subclass or delegate by default.
 *
 * <p>The {@code suppressInterface} method can be used to suppress interfaces
 * implemented by the delegate but which should not be introduced to the owning
 * AOP proxy.
 *
 * <p>An instance of this class is serializable if the delegate is.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 16.11.2003
 * @see #suppressInterface
 * @see DelegatePerTargetObjectIntroductionInterceptor
 */
@SuppressWarnings("serial")
public class DelegatingIntroductionInterceptor extends IntroductionInfoSupport
		implements IntroductionInterceptor {

	/**
	 * Object that actually implements the interfaces.
	 * May be "this" if a subclass implements the introduced interfaces.
	 */
	@Nullable
	private Object delegate;


	/**
	 * Construct a new DelegatingIntroductionInterceptor, providing
	 * a delegate that implements the interfaces to be introduced.
	 * @param delegate the delegate that implements the introduced interfaces
	 */
	public DelegatingIntroductionInterceptor(Object delegate) {
		// 这里是通过一个独立的delegate来实现要引入的所有接口
		// 然后通过构造方法初始化 delegate 字段
		init(delegate);
	}

	/**
	 * Construct a new DelegatingIntroductionInterceptor.
	 * The delegate will be the subclass, which must implement
	 * additional interfaces.
	 * 如果不传一个独立的 delegate,说明子类自己就是 delegate
	 * ,子类必须实现 要引入的所有接口
	 */
	protected DelegatingIntroductionInterceptor() {
		init(this);
	}


	/**
	 * Both constructors use this init method, as it is impossible to pass
	 * a "this" reference from one constructor to another.
	 * @param delegate the delegate object
	 */
	private void init(Object delegate) {
		Assert.notNull(delegate, "Delegate must not be null");
		this.delegate = delegate;
		// 这里会调用 IntroductionInfoSupport.implementInterfacesOnObject()
		// 将 delegate 所实现的所有接口提出出来,并发布
		implementInterfacesOnObject(delegate);

		// We don't want to expose the control interface
		suppressInterface(IntroductionInterceptor.class);
		suppressInterface(DynamicIntroductionAdvice.class);
	}


	/**
	 * Subclasses may need to override this if they want to perform custom
	 * behaviour in around advice. However, subclasses should invoke this
	 * method, which handles introduced interfaces and forwarding to the target.
	 * 如果子类想执行以下自定义的行为,就需要重写这个方法,然而,子类需要通过调用
	 * super.invoke(mi)调用这个方法,这个方法可以处理引入的接口,并将调用转发到
	 * delegate
	 */
	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		// 调用IntroductionInfoSupport.isMethodOnIntroducedInterface()是不是属于
		// 被引入的接口之一
		if (isMethodOnIntroducedInterface(mi)) {
			// Using the following method rather than direct reflection, we
			// get correct handling of InvocationTargetException
			// if the introduced method throws an exception.
			
			// 如果判断这个Method是属于被引入的某一个接口,说明delegate能解决问题
			// 调用delegate的方法完成调用的任务
			Object retVal = AopUtils.invokeJoinpointUsingReflection(this.delegate, mi.getMethod(), mi.getArguments());

			// Massage return value if possible: if the delegate returned itself,
			// we really want to return the proxy.
			if (retVal == this.delegate && mi instanceof ProxyMethodInvocation) {
				Object proxy = ((ProxyMethodInvocation) mi).getProxy();
				if (mi.getMethod().getReturnType().isInstance(proxy)) {
					retVal = proxy;
				}
			}
			return retVal;
		}
		// 如果不属于被引入的任何一个接口,就掉过当前 MethodInterceptor
		return doProceed(mi);
	}

	/**
	 * Proceed with the supplied {@link org.aopalliance.intercept.MethodInterceptor}.
	 * Subclasses can override this method to intercept method invocations on the
	 * target object which is useful when an introduction needs to monitor the object
	 * that it is introduced into. This method is <strong>never</strong> called for
	 * {@link MethodInvocation MethodInvocations} on the introduced interfaces.
	 */
	@Nullable
	protected Object doProceed(MethodInvocation mi) throws Throwable {
		// If we get here, just pass the invocation on.
		return mi.proceed();
	}

}



/**
 * Support for implementations of {@link org.springframework.aop.IntroductionInfo}.
 * 
 * <p>Allows subclasses to conveniently add all interfaces from a given object,
 * and to suppress interfaces that should not be added. Also allows for querying
 * all introduced interfaces.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
@SuppressWarnings("serial")
public class IntroductionInfoSupport implements IntroductionInfo, Serializable {

	protected final Set<Class<?>> publishedInterfaces = new LinkedHashSet<>();

	private transient Map<Method, Boolean> rememberedMethods = new ConcurrentHashMap<>(32);


	/**
	 * Suppress the specified interface, which may have been autodetected
	 * due to the delegate implementing it. Call this method to exclude
	 * internal interfaces from being visible at the proxy level.
	 * <p>Does nothing if the interface is not implemented by the delegate.
	 * @param ifc the interface to suppress
	 */
	public void suppressInterface(Class<?> ifc) {
		this.publishedInterfaces.remove(ifc);
	}
	
	// 返回子类中的 delegate 所实现的所有接口
	// 用于校验本次调用的Method是不是属于 子类的 delegate 所实现的所有接口
	// 之一
	@Override
	public Class<?>[] getInterfaces() {
		return ClassUtils.toClassArray(this.publishedInterfaces);
	}

	/**
	 * 校验传入的接口是不是 发布的被引入的接口之一
	 * Check whether the specified interfaces is a published introduction interface.
	 * @param ifc the interface to check
	 * @return whether the interface is part of this introduction
	 */
	public boolean implementsInterface(Class<?> ifc) {
		for (Class<?> pubIfc : this.publishedInterfaces) {
			if (ifc.isInterface() && ifc.isAssignableFrom(pubIfc)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 发布 delegate 所实现的所有接口,子类中调用。delegate是子类传的
	 * Publish all interfaces that the given delegate implements at the proxy level.
	 * @param delegate the delegate object
	 */
	protected void implementInterfacesOnObject(Object delegate) {
		this.publishedInterfaces.addAll(ClassUtils.getAllInterfacesAsSet(delegate));
	}

	/**
	 * 校验MethodInvocation实例中的Method对象是不是属于被引入的某一个接口
	 * Is this method on an introduced interface?
	 * @param mi the method invocation
	 * @return whether the invoked method is on an introduced interface
	 */
	protected final boolean isMethodOnIntroducedInterface(MethodInvocation mi) {
		Boolean rememberedResult = this.rememberedMethods.get(mi.getMethod());
		if (rememberedResult != null) {
			return rememberedResult;
		}
		else {
			// Work it out and cache it.
			boolean result = implementsInterface(mi.getMethod().getDeclaringClass());
			this.rememberedMethods.put(mi.getMethod(), result);
			return result;
		}
	}

}

举两个例子:

例子一:

public interface CarService {
    Integer addCar(Car car);
}


public interface AService {

    public String serviceA(String param);

    public String serviceAA(String param);

}


public interface BService {
    public String serviceB(String param);
    public String serviceBB(String param);
}
public class CarServiceImpl implements CarService, AService, BService {

    @Override
    public Integer addCar(Car car) {
        System.out.println("add");
        //int i = 1 / 0;
        return 1000;
    }

    @Override
    public String serviceA(String param) {
        System.out.println("执行 CarServiceImpl.serviceA() 参数:" + param);
        return "CarServiceImpl.serviceA() 处理过的 " + param;
    }

    @Override
    public String serviceAA(String param) {
        System.out.println("执行 CarServiceImpl.serviceAA() 参数:" + param);
        return "CarServiceImpl.serviceAA() 处理过的 " + param;
    }

    @Override
    public String serviceB(String param) {
        System.out.println("执行 CarServiceImpl.serviceB() 参数:" + param);
        return "CarServiceImpl.serviceB() 处理过的 " + param;
    }

    @Override
    public String serviceBB(String param) {
        System.out.println("执行 CarServiceImpl.serviceBB() 参数:" + param);
        return "CarServiceImpl.serviceBB() 处理过的 " + param;
    }
}
public class ProxyFactoryTest1 {

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory();

        CarServiceImpl carServiceImpl = new CarServiceImpl();

        DelegatingIntroductionInterceptor delegatingIntroductionInterceptor = new DelegatingIntroductionInterceptor(carServiceImpl);

        IntroductionAdvisor introductionAdvisor = new DefaultIntroductionAdvisor(delegatingIntroductionInterceptor);

        proxyFactory.addAdvisor(introductionAdvisor);
        
        CarService carServiceProxy = (CarService) proxyFactory.getProxy();
        Integer integer = carServiceProxy.addCar(new Car());
        System.out.println(integer);

        AService aServiceProxy = (AService) proxyFactory.getProxy();
        String serviceA = aServiceProxy.serviceA("测试引入代理");
        System.out.println(serviceA);

        BService bServiceProxy = (BService) proxyFactory.getProxy();
        String serviceBB = bServiceProxy.serviceBB("测试引入代理");
        System.out.println(serviceBB);

    }

}


运行结果:
add
1000
执行 CarServiceImpl.serviceA() 参数:测试引入代理
CarServiceImpl.serviceA() 处理过的 测试引入代理
执行 CarServiceImpl.serviceBB() 参数:测试引入代理
CarServiceImpl.serviceBB() 处理过的 测试引入代理

例子二:

public class CustomDelegatingIntroductionInterceptor extends DelegatingIntroductionInterceptor implements CarService,AService,BService {
    @Override
    public Integer addCar(Car car) {
        System.out.println("执行 CustomDelegatingIntroductionInterceptor.add() 参数:" + JSON.toJSONString(car));
        return 2000;
    }

    @Override
    public String serviceA(String param) {
        System.out.println("执行 CustomDelegatingIntroductionInterceptor.serviceA() 参数:" + param);
        return "CustomDelegatingIntroductionInterceptor.serviceA() 处理过的 " + param;
    }

    @Override
    public String serviceAA(String param) {
        System.out.println("执行 CustomDelegatingIntroductionInterceptor.serviceAA() 参数:" + param);
        return "CustomDelegatingIntroductionInterceptor.serviceAA() 处理过的 " + param;
    }

    @Override
    public String serviceB(String param) {
        System.out.println("执行 CustomDelegatingIntroductionInterceptor.serviceB() 参数:" + param);
        return "CustomDelegatingIntroductionInterceptor.serviceB() 处理过的 " + param;
    }

    @Override
    public String serviceBB(String param) {
        System.out.println("执行 CustomDelegatingIntroductionInterceptor.serviceBB() 参数:" + param);
        return "CustomDelegatingIntroductionInterceptor.serviceBB() 处理过的 " + param;
    }
}
public class ProxyFactoryTest2 {

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory();

        IntroductionAdvisor introductionAdvisor = new DefaultIntroductionAdvisor(new CustomDelegatingIntroductionInterceptor());
        proxyFactory.addAdvisor(introductionAdvisor);

        CarService carServiceProxy = (CarService) proxyFactory.getProxy();
        Integer integer = carServiceProxy.addCar(new Car());
        System.out.println(integer);

        AService aServiceProxy = (AService) proxyFactory.getProxy();
        String serviceA = aServiceProxy.serviceA("测试引入代理");
        System.out.println(serviceA);

        BService bServiceProxy = (BService) proxyFactory.getProxy();
        String serviceBB = bServiceProxy.serviceBB("测试引入代理");
        System.out.println(serviceBB);
        
    }

}

执行结果:
执行 CustomDelegatingIntroductionInterceptor.add() 参数:{}
2000
执行 CustomDelegatingIntroductionInterceptor.serviceA() 参数:测试引入代理
CustomDelegatingIntroductionInterceptor.serviceA() 处理过的 测试引入代理
执行 CustomDelegatingIntroductionInterceptor.serviceBB() 参数:测试引入代理
CustomDelegatingIntroductionInterceptor.serviceBB() 处理过的 测试引入代理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/925754.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pytest使用Jpype调用jar包报错:Windows fatal exception: access violation

问题描述 ​   之前我们有讲过如何使用Jpype调用jar包&#xff0c;在成功调用jar包后&#xff0c;接着在Pytest框架下编写自动测试用例。但是在Pytest下使用Jpype加载jar包&#xff0c;并调用其中的方法会以下提示信息&#xff1a; ​   虽然提示信息显示有Windows显示致命…

RVO动态避障技术方案介绍

原文&#xff1a;RVO动态避障技术方案介绍 - 哔哩哔哩 我们在开发游戏的时候经常会遇到这样的问题&#xff0c;当我们寻路的时候&#xff0c;其它人也在寻路&#xff0c;如何避免不从其它人的位置穿过。这个叫做动态避障&#xff0c;目前主流的解决方案就是RVO。本节我们来介绍…

浅谈人工智能之基于容器云进行图生视频大模型搭建

浅谈人工智能之基于容器云进行图生视频大模型搭建 根据之前我们所讲过的内容&#xff1a; 文生图 文生视频 我们继续讲解图生视频大模型搭建。 引言 随着深度学习技术的不断发展&#xff0c;图生视频&#xff08;image-to-video&#xff09;大模型成为了计算机视觉和自然语言…

十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize

1. AJAX介绍及axios基本使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content&q…

【微服务】 Eureka和Ribbon

一、Eureka 服务调用出现的问题&#xff1a;在远程调用另一个服务时&#xff0c;我们采用的解决办法是发送一次http请求&#xff0c;每次环境的变更会产生新的地址&#xff0c;所以采用硬编码会出现很多麻烦&#xff0c;并且为了应对并发问题&#xff0c;采用分布式部署&#…

安卓-碎片的使用入门

1.碎片(Fragment)是什么 Fragment是依赖于Activity的&#xff0c;不能独立存在的,是Activity界面中的一部分&#xff0c;可理解为模块化的Activity,它能让程序更加合理和充分地利用大屏幕的空间&#xff0c;因而在平板上应用得非常广泛. Fragment不能独立存在&#xff0c;必须…

Emgu (OpenCV)

Emgu Github Emgu 环境&#xff1a; Emgu CV 4.9.0 netframework 4.8 1、下载 libemgucv-windesktop-4.9.0.5494.exe 安装后&#xff0c;找到安装路径下的runtime文件夹复制到c#项目Debug目录下 安装目录 c# Debug目录

Stripe测试

通过官方提供的Stripe-cli工具进行测试。 1. 下载Stripe-cli 下载链接&#xff1a;Release v1.17.1 stripe/stripe-cli GitHub 2. 获取密钥 进入到stripe控制台测试模式 查看API密钥 3. 测试 指定您的API 私钥 stripe login --api-key sk_test_51ISwaXTwNwO1Rvw32DNG10…

第J7周:对于RenseNeXt-50算法的思考

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 文章目录 一、前言1、导入包2、分组卷积模块3、残差单元4、堆叠残差单元5、搭建ResNeXt-50网络 二、问题思考 电脑环境&#xff1a; 语言环境&#xff1a;Pyth…

React第十节组件之间传值之context

1、Context 使用creatContext() 和 useContext() Hook 实现多层级传值 概述&#xff1a; 在我们想要每个层级都需要某一属性&#xff0c;或者祖孙之间需要传值时&#xff0c;我们可以使用 props 一层一层的向下传递&#xff0c;或者我们使用更便捷的方案&#xff0c;用 creatC…

WPF DataGrid 列隐藏

Window节点加上下面的 <Window.Resources><FrameworkElement x:Key"ProxyElement" DataContext"{Binding}" /></Window.Resources>然后随便加一个隐藏控件 <ContentControl Content"{StaticResource ProxyElement}" Visi…

【娱乐项目】基于cnchar库与JavaScript的汉字查询工具

Demo介绍 利用了 cnchar 库来进行汉字相关的信息查询&#xff0c;并展示了汉字的拼音、笔画数、笔画顺序、笔画动画等信息用户输入一个汉字后&#xff0c;点击查询按钮&#xff0c;页面会展示该汉字的拼音、笔画数、笔画顺序&#xff0c;并绘制相应的笔画动画和测试图案 cnchar…

sqoop import报错java.lang.NullPointerException

场景&#xff1a;从TDSQL抽数到hdfs报错&#xff0c;需要指定驱动类名 报错如下&#xff1a; java.lang.RuntimeException: java.lang.NullPointerException Caused by: java.lang.RuntimeException: java.lang.NullPointerException 修改前抽数脚本&#xff1a; #执行sqoo…

小程序 - 个人简历

为了让招聘人员快速地认识自己&#xff0c;可以做一个“个人简历”微信小程序&#xff0c; 展示自己的个人信息。 下面将对“个人简历”微信小程序进行详细讲解。 目录 个人简历 创建图片目录 页面开发 index.wxml index.wxss 功能实现截图 总结 个人简历 创建图片目录…

接口性能优化宝典:解决性能瓶颈的策略与实践

目录 一、直面索引 &#xff08;一&#xff09;索引优化的常见场景 &#xff08;二&#xff09;如何检查索引的使用情况 &#xff08;三&#xff09;如何避免索引失效 &#xff08;四&#xff09;强制选择索引 二、提升 SQL 执行效率 &#xff08;一&#xff09;避免不必…

通过金蝶云星空实现高效仓储管理

金蝶云星空数据集成到旺店通WMS的技术案例分享 在企业日常运营中&#xff0c;库存管理和物流调度是至关重要的环节。为了实现高效的数据流转和业务协同&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将金蝶云星空的数据无缝对接到旺店通WMS。本次案例聚焦于“调拨入库…

数字IC后端实现之PR工具中如何避免出现一倍filler的缝隙?

在数字IC后端实现中&#xff0c;由于有的工艺foundary不提供Filler1&#xff0c;所以PR工具Innovus和ICC2在做标准单元摆放时需要避免出现两个标准单元之间的缝隙间距是Filler1。为了实现这个目的&#xff0c;我们需要给PR工具施加一些特殊的placement constraint&#xff08;典…

【React】全局状态管理(Context, Reducer)

以下为知行小课学习笔记。 概述 Context 跨组件共享状态 在 Next 项目&#xff0c;封装 useContext。 AppContext.tsx "use client";import React, {createContext, Dispatch, ReactNode, SetStateAction, useContext, useMemo, useState} from react;type State …

【游资悟道】-作手新一悟道心法

作手新一经典语录节选&#xff1a; 乔帮主传完整版&#xff1a;做股票5年&#xff0c;炼成18式&#xff0c;成为A股低吸大神&#xff01;从小白到大神&#xff0c;散户炒股的六个过程&#xff0c;不看不知道自己水平 围着主线做&#xff0c;多研究龙头&#xff0c;研究涨停&am…

Sqoop的安装和配置,Sqoop的数据导入导出,MySQL对hdfs数据的操作

sqoop的安装基础是hive和mysql&#xff0c;没有安装好的同学建议去看一看博主的这一篇文章 Hive的部署&#xff0c;远程模式搭建&#xff0c;centos换源&#xff0c;linux上下载mysql。_hive-4.0.1-CSDN博客 好的那么接下来我们开始表演&#xff0c;由于hive是当时在hadoop03上…