Creation of proxy in spring

A little bit 2021-04-16 17:56:01
creation proxy spring


[toc]

spring Agent creation


spring Creating a proxy in uses Jdk and Cglib Two ways to create ,JdkDynamicAopProxy and ObjenesisCglibAopProxy, By using configuration Advised and ProxyConfig To manage configuration , Decide which way to create the proxy based on the configuration , Here are some key classes .

Advised

​ Advised It's a management AOP The interface configured by the agent factory , stay spring All in AopProxy Can be converted into Advised.

ProxyConfig

stay spring in , Use ProxyConfig To configure the proxy creation properties .

/**
* Super class of agent factory , Properties for unified management of agent factory classes .
*/
public class ProxyConfig implements Serializable {
// true: Using subclass proxies ,false: Using the interface proxy 
private boolean proxyTargetClass = false;
// Start agent optimization 
private boolean optimize = false;
// Whether the agent created by the agent foreman can be converted to Advised, The default is false: Can be said ,
// If false, Can be bean Convert to Advised:Advised testBean = (Advised) context.getBean("testBean");
boolean opaque = false;
// Expose the agent , Bound to the ThreadLocal Of currentProxy, For the proxy class's own method to call its own scenario .
boolean exposeProxy = false;
// Freeze configuration ,true: The configuration of the agent foreman cannot be modified .
private boolean frozen = false;
}

Realized ProxyConfig The immediate subclass of is 4 individual :

ScopedProxyFactoryBean、ProxyProcessorSupport、AbstractSingletonProxyFactoryBean、AdvisedSupport, These classes use different ways to create proxies , But in the end, the creation of the agent will be delegated to ProxyFactory, Let's take a look at 4 Code related to a direct subclass .

  1. ScopedProxyFactoryBean: be used for @Scope annotation , Realization bean Scope control of . He did BeanFactoryBeanFactoryAware Interface , With creation 、 management bean The ability of .

    The proxy generated by this class only records the name of the class , Then get... According to the scope bean, If it is prototype Of , be beanFactory It will create a new one bean.

    public class ScopedProxyFactoryBean extends ProxyConfig
    implements FactoryBean<Object>, BeanFactoryAware, AopInfrastructureBean{
    // Use it to manage bean Scope of action , His implementation is very simple , When you get an object , Entrusted to beanFactory, then beanFactory Get the corresponding... According to the scope bean.
    private final SimpleBeanTargetSource scopedTargetSource = new SimpleBeanTargetSource();
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
    if (!(beanFactory instanceof ConfigurableBeanFactory)) {
    throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
    }
    ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
    // take beanFactory And scopedTargetSource relation , When getting the proxy target class , from scopedTargetSource In order to get ,
    // SimpleBeanTargetSource Will get bean The operation of is delegated to beanFactory
    this.scopedTargetSource.setBeanFactory(beanFactory);
    ProxyFactory pf = new ProxyFactory();
    pf.copyFrom(this);
    pf.setTargetSource(this.scopedTargetSource);
    Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
    Class<?> beanType = beanFactory.getType(this.targetBeanName);
    if (beanType == null) {
    throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
    "': Target type could not be determined at the time of proxy creation.");
    }
    // Using the interface proxy 
    if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
    pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader()));
    }
    // Simple proxy enhancement , When calling the proxy class , from beanFactory In order to get bean To call , In this way, the scope is controlled .
    ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
    pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));
    // Does the token proxy need to be AOP Intercept , There are entry points to match in time 
    pf.addInterface(AopInfrastructureBean.class);
    // Create a proxy object : Give the creation agent to ProxyFactory
    this.proxy = pf.getProxy(cbf.getBeanClassLoader());
    }
    }
    
  2. ProxyProcessorSupport: by ProxyFactory Provides common public methods .

public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanClassLoaderAware, AopInfrastructureBean {
/**
* You can customize the sort
*/
public void setOrder(int order) { this.order = order; }
@Override
public int getOrder() { return this.order; }
/**
* When the interface is implemented , Using the interface proxy , If the interface is not implemented, the class proxy is used .
*/
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false;
for (Class<?> ifc : targetInterfaces) {
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
ifc.getMethods().length > 0) {
hasReasonableProxyInterface = true;
break;
}
}
if (hasReasonableProxyInterface) {
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
}
else {
proxyFactory.setProxyTargetClass(true);
}
}
}
  1. AbstractSingletonProxyFactoryBean : Create singleton proxy objects , After instantiating the object that needs to be represented , Use InitializingBean#afterPropertiesSet() To create an agent , And set pre notification and post notification for it .

    public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
    implements FactoryBean<Object>, BeanClassLoaderAware, InitializingBean {
    // Proxy target object 
    private Object target;
    // The interface of the proxy is required 
    private Class<?>[] proxyInterfaces;
    // Front interceptor 
    private Object[] preInterceptors;
    // Post blocker 
    private Object[] postInterceptors;
    // overall situation Advisor Registrar 
    private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
    // Class loader 
    private transient ClassLoader proxyClassLoader;
    // Proxy object 
    private Object proxy;
    // After instantiation calls 
    @Override
    public void afterPropertiesSet() {
    // ....
    // Delegate agent creation to ProxyFactory
    ProxyFactory proxyFactory = new ProxyFactory();
    // The preprocessor 、 Main processor 、 The postprocessor adds... In order , A processor chain can be formed to execute all processors according to the order of addition .
    // Add preprocessor 
    if (this.preInterceptors != null) {
    for (Object interceptor : this.preInterceptors) {
    proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
    }
    }
    // Add the main processor , Give it to the subclass implementation 
    proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
    // Add post processor 
    if (this.postInterceptors != null) {
    for (Object interceptor : this.postInterceptors) {
    proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
    }
    }
    // Copy properties 
    proxyFactory.copyFrom(this);
    // Create proxy target source : The default is SingletonTargetSource 
    TargetSource targetSource = createTargetSource(this.target);
    proxyFactory.setTargetSource(targetSource);
    // Set the agent's interface 
    if (this.proxyInterfaces != null) {
    proxyFactory.setInterfaces(this.proxyInterfaces);
    }
    // If you don't use class proxies , Resolve the interface of the target class .
    else if (!isProxyTargetClass()) {
    // Rely on AOP infrastructure to tell us what interfaces to proxy.
    Class<?> targetClass = targetSource.getTargetClass();
    if (targetClass != null) {
    proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
    }
    }
    // Agent factory post processing method , Implemented by subclasses , Change agent configuration 
    postProcessProxyFactory(proxyFactory);
    // Create proxy object , Entrusted to ProxyFactory
    this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
    }
    }
    
  2. AdvisedSupport: Realized Advised, take ProxyConfig And Advised ADAPTS , by Advised Provided support , His only subclass ProxyCreatorSupport Provides support for proxy creation .

    public class AdvisedSupport extends ProxyConfig implements Advised {
    // Empty proxy object 
    public static final TargetSource EMPTY_TARGET_SOURCE = EmptyTargetSource.INSTANCE;
    // Proxy target source : The default is empty target source 
    TargetSource targetSource = EMPTY_TARGET_SOURCE;
    // Whether or not it has been right Advisors It's been over considered 
    private boolean preFiltered = false;
    // Advisor Call chain foreman 
    AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
    // The cache method corresponds to Advisor Call chain .
    private transient Map<MethodCacheKey, List<Object>> methodCache;
    // The proxy interface to implement , Store in order .
    private List<Class<?>> interfaces = new ArrayList<>();
    // Advisor list 
    private List<Advisor> advisors = new ArrayList<>();
    // Advisor data , To facilitate internal operation .
    private Advisor[] advisorArray = new Advisor[0];
    }
    

    ProxyCreatorSupport Provides support for proxy creation , He used AopProxyFactory To create AopProxy, Last ProxyFactory Use AopProxy To create a proxy object .

    Creating ProxyCreatorSupport Created by default DefaultAopProxyFactory, It's up to him to decide whether to use an interface proxy or a subclass proxy .

    public class ProxyCreatorSupport extends AdvisedSupport {
    private AopProxyFactory aopProxyFactory;
    private final List<AdvisedSupportListener> listeners = new LinkedList<>();
    // After the first agent is created, it will be set to true, Means to enter an active state , Will trigger listeners.
    private boolean active = false;
    /**
    * Parameterless constructors , A default will be created aopProxyFactory.
    * DefaultAopProxyFactory Is a foreman who creates an agent , Used to create agents based on configuration .
    */
    public ProxyCreatorSupport() {
    this.aopProxyFactory = new DefaultAopProxyFactory();
    }
    // establish AOP agent , According to its own configuration properties, I feel like using JDK The agent or Cglib agent .
    protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
    activate();
    }
    return getAopProxyFactory().createAopProxy(this);
    }
    }
    

    ​ The use of DefaultAopProxyFactory To decide to use jdk The agent or Cglib agent , He received a AdvisedSupport

    // AopProxy factory 
    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // Enable optimization or use subclass proxies 、 No interface implemented , You'll use the subclass proxy approach .
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
    Class<?> targetClass = config.getTargetClass();
    if (targetClass == null) {
    throw new AopConfigException("TargetSource cannot determine target class: " +
    "Either an interface or a target is required for proxy creation.");
    }
    // The proxy target is the interface , Or a proxy object , Use jdk agent , Otherwise use Cglib agent 
    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
    }
    return new ObjenesisCglibAopProxy(config);
    }
    // Using the interface proxy :JDK agent 
    else {
    return new JdkDynamicAopProxy(config);
    }
    }
    }
    

    ProxyFactory yes ProxyCreatorSupport Subclasses of , Get... By calling the method of the parent class AopProxy To create the target proxy object .

    public class ProxyFactory extends ProxyCreatorSupport {
    public Object getProxy() {
    // Drop out `ProxyCreatorSupport#createAopProxy` Method and then use it according to the configuration JDK Generating a proxy or Cglib Build agent 
    return createAopProxy().getProxy();
    }
    // The difference from the above method is that the class loader is passed in 
    public Object getProxy(@Nullable ClassLoader classLoader) {
    return createAopProxy().getProxy(classLoader);
    }
    }
    
JdkDynamicAopProxy
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** Agent configuration . */
private final AdvisedSupport advised;
/**
* Whether the agent interface defines equals Method
*/
private boolean equalsDefined;
/**
* Whether the agent's interface is defined hashCode Method
*/
private boolean hashCodeDefined;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
// Notification not empty , And the target source is not empty .
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
// To create the agent 
@Override
public Object getProxy() {
// Pass in the default class loader 
return getProxy(ClassUtils.getDefaultClassLoader());
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// Get all interfaces of the proxy target class 
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// Check if the interface is implemented equals and hashCode Method 
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// Create proxy object , Here comes this object , because JdkDynamicAopProxy Realized InvocationHandler, Use this piece of proxy logic to proxy 
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
/**
* aop Proxy usage jdk The logic that the agent will execute
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// perform equals When the method is used , Interface not defined equals Method , perform JdkDynamicAopProxy Of equals Method 
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
// perform hashCode When the method is used , Interface not defined hashCode Method , perform JdkDynamicAopProxy Of hashCode Method 
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
// 
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
// Can be converted to Advised, Convert to Advised, And then execute 
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// Whether to expose the current agent , Bound to the ThreadLocal in ,
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get target object 
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get pointcuts based on proxy target objects and methods 、 Methods, interceptors, etc .
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// If the interceptor or notification that matches the method is empty , Then make a direct call , Avoid creating MethodInvocation
if (chain.isEmpty()) {
// Find a way 
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// Call the original object method directly 
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// call The breakthrough point 、 method interceptors , Target class 
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// 
Class<?> returnType = method.getReturnType();
// If the return value is the target object , And the proxy object is an instance of the return value type , Replace the return value with the proxy object 
// Method's declaration class is not implemented RawTargetAccess
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
retVal = proxy;
}
// If the return value type is the underlying data type , And for null.
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
}

stay JdkDynamicAopProxy in , Yes 2 Key code ,1 Is the interface to get the proxy target ,2 It's the execution entry point 、 Interceptor .

  1. AopProxyUtils#completeProxiedInterfaces() Method to get the interface of the proxy target , Add some interfaces according to the rules SpringProxy、Advised、DecoratingProxy.

    // AopProxyUtils
    static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
    // Get the interface implemented by the target class 
    Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
    // The interface of the target class is empty 
    if (specifiedInterfaces.length == 0) {
    // Get proxy targets class
    Class<?> targetClass = advised.getTargetClass();
    if (targetClass != null) {
    // Determine whether the target type is an interface 
    if (targetClass.isInterface()) {
    advised.setInterfaces(targetClass);
    }
    // The proxy target type is proxy 
    else if (Proxy.isProxyClass(targetClass)) {
    advised.setInterfaces(targetClass.getInterfaces());
    }
    // Reacquire the interface set of the proxy object 
    specifiedInterfaces = advised.getProxiedInterfaces();
    }
    }
    // If the target class is not implemented SpringProxy Interface , Will add SpringProxy To the interface set .
    boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
    // The target class can be converted to Advised, And it's not realized Advised Interface , Then add Advised To the interface set 
    boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
    // decoratingProxy by true, And the target class is not implemented DecoratingProxy Interface , take DecoratingProxy Add to the interface set 
    boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
    // Divide the interface array length 
    int nonUserIfcCount = 0;
    if (addSpringProxy) {
    nonUserIfcCount++;
    }
    if (addAdvised) {
    nonUserIfcCount++;
    }
    if (addDecoratingProxy) {
    nonUserIfcCount++;
    }
    Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
    // Copy 
    System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
    // Interface class Set into the corresponding array position 
    int index = specifiedInterfaces.length;
    if (addSpringProxy) {
    proxiedInterfaces[index] = SpringProxy.class;
    index++;
    }
    if (addAdvised) {
    proxiedInterfaces[index] = Advised.class;
    index++;
    }
    if (addDecoratingProxy) {
    proxiedInterfaces[index] = DecoratingProxy.class;
    }
    // Returns the set of interfaces that require a proxy .
    return proxiedInterfaces;
    }
    
  2. Execute aspect and method interceptor logic ReflectiveMethodInvocation#proceed

    public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    public Object proceed() throws Throwable {
    // Notify or intercept after execution , Business methods will be executed 
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
    return invokeJoinpoint();
    }
    // Get notifications or interceptors 
    Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    // Notification or interceptor is InterceptorAndDynamicMethodMatcher 
    // InterceptorAndDynamicMethodMatcher Used to combine method matchers with interceptors , If the method matcher matches, it is called with interceptor 
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
    InterceptorAndDynamicMethodMatcher dm =
    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
    Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
    if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
    return dm.interceptor.invoke(this);
    }
    else {
    // Matching failure , Call the next matching interceptor 
    return proceed();
    }
    }
    // Call other interceptors , Other interceptors need to call , Because of the introduction of this, Interceptor chain can use reference to call this method , To execute the next slice or interceptor .
    else {
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
    }
    }
    
版权声明
本文为[A little bit]所创,转载请带上原文链接,感谢
https://javamana.com/2021/04/20210416160044393F.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云