根据动态代理手写一个AOP

3 篇文章 0 订阅
订阅专栏

目录

功能列表

一、定义切面接口

二、定义ProxyFactory 

JDKProxyFactory

CglibProxyFactory

三、ServiceLoader兼顾可插拔性

四、默认使用Cglib创建代理对象

五、代理核心实现 

六、ProxyUtil 

七、自定义切面类


        SpringAop是面向切面编程的实现手段,也是动态代理的表现,我们可以借助SpringAOP在应用里来实现一个切面,可管理应用的日志、安全和事务等功能,只需要用@Aspect 注解标记一个类为切面,用@Pointcut注解定义一组service为一个切点, 然后定义方法的通知类型即可完成一个Aop的定义。

        抛开SpringAOP, 使用JDK 动态代理和Cglib 动态代理如何实现对象的动态代理,对外只需要提供目标对象和切面类,实现对目标对象的环绕通知和异常处理。

功能列表

1. 统一切面的通知模式,模式包含前置通知、后置通知和异常处理,SpringAop环绕通知也就是前置通知和后置通知的结合。

2. 能定制切面,可以对切面进行二次开发,如一组功能类似的类使用同一个切面。

3. 默认采用Cglib 生成代理对象,因为JDK动态代理需要目标对象实现额外的接口。

4. 只要提供目标对象和自定义的切面类即可生成代理对象,实现的目标如下:

FixPhone fixPhone = ProxyUtil.Proxy(new FixPhone(), MyAspect.class);

一、定义切面接口

        切面接口只需要包含3个方法before、after和throwException, 主要包含3个参数分别是目标类对象的实例、目标方法对象和目标方法的参数。

package com.bing.sh.aop.aspect;

import java.lang.reflect.Method;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/18 0018 23:12
 */
public interface Aspect {


    /**
     * 目标方法执行前
     * @param target
     * @param method
     * @param args
     * @return
     */
    boolean before(Object target, Method method, Object[] args);


    /**
     * 目标方法执行后
     * @param target
     * @param method
     * @param args
     * @param returnValue
     * @return
     */
    boolean after(Object target, Method method, Object[] args, Object returnValue);


    /**
     * 目标方法调用异常
     * @param target
     * @param method
     * @param args
     * @param throwable
     * @return
     */
    boolean throwException(Object target, Method method, Object[] args, Throwable throwable);

}

        下面使用工厂模式去生产2种代理实现,分别是JDKProxyFactory和CglibProxyFactory。

二、定义ProxyFactory 

        定义抽象类ProxyFactory, 由JDKProxyFactory和CglibProxyFactory实现。

public abstract class ProxyFactory implements Serializable {

    private static final long serialVersionUID = 122319479213L;




    /**
     * 执行代理
     */
    public abstract <T> T proxy(T target, Aspect aspect);

}

JDKProxyFactory

        我们可以直接使用java.lang.reflect包下的Proxy对象调用newProxyInstance创建代理对象,参数Class<?>[] interfaces为目标对象实现的接口列表,InvocationHandler 接口需要我们自己去实现。

    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h) {
        Objects.requireNonNull(h);

        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
    }
package com.bing.sh.aop.proxy;

import com.bing.sh.aop.aspect.Aspect;
import com.bing.sh.aop.interceptor.JDKInterceptor;

import java.lang.reflect.Proxy;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/18 0018 23:14
 */
public class JDKProxyFactory extends ProxyFactory {


    @Override
    public <T> T proxy(T target, Aspect aspect) {
        JDKInterceptor interceptor = new JDKInterceptor(target, aspect);
        return  (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
        
    }
}

CglibProxyFactory

        我们在使用Cglilb生成代理对象时,需要添加cglib的dependency,借助Enhancer创建代理对象 。

  <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
</dependency>
package com.bing.sh.aop.proxy;


import com.bing.sh.aop.aspect.Aspect;
import com.bing.sh.aop.interceptor.CglibInterceptor;
import net.sf.cglib.proxy.Enhancer;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/18 0018 23:14
 */
public class CglibProxyFactory extends ProxyFactory {


    @Override
    public <T> T proxy(T target, Aspect aspect) {
        final Enhancer enhancer = new Enhancer();
        // super class 为目标对象的class。
        enhancer.setSuperclass(target.getClass());
        //设置callback, 就是MethodInterceptor的接口的实现类
        enhancer.setCallback(new CglibInterceptor(target, aspect));
        return (T) enhancer.create();
    }
}

三、ServiceLoader兼顾可插拔性

        为了提高应用的可插拔性,JDK提供了一个SPI给我们开发者,我们可以使用JDK里的ServerLoader类去加载META-INF/services目录下文件名定义的类实现。

        这也是JDK对开发者提供的一种SPI机制,当我们对一个接口或抽象类有多个实现时,我们在选择实现类的时候,只需要从多个实现中选择一个即可,如果没有该配置,我们也可以使用一个默认的实现,配置的方式全限定名的方式,如下:

         一般实现只配置一个就行,比如Spring框架里的spring-web模块,实现了servlet提供的初始化接口javax.servlet.ServletContainerInitializer,实现类为:org.springframework.web.SpringServletContainerInitializer。

        我在项目里的com.bing.sh.aop.proxy.ProxyFactory 抽象类有2个实现,分别是CglibProxyFactory和JDKProxyFactory, 那么我们可以直接将CglibProxyFactory和JDKProxyFactory的全限定名配置到该文件里。

        ServiceLoader类提供了一个静态方法load 去加载META-INF/services目录下的clazz和对应的实现:

Params:
service – The interface or abstract class representing the service
loader – The class loader to be used to load provider-configuration files and provider classes, or null if the system class loader (or, failing that, the bootstrap class loader) is to be used
Type parameters:
<S> – the class of the service type
Returns:
A new service loader
Throws:
ServiceConfigurationError – if the service type is not accessible to the caller or the caller is in an explicit module and its module descriptor does not declare that it uses service
API Note:
If the class path of the class loader includes remote network URLs then those URLs may be dereferenced in the process of searching for provider-configuration files.
This activity is normal, although it may cause puzzling entries to be created in web-server logs. If a web server is not configured correctly, however, then this activity may cause the provider-loading algorithm to fail spuriously.
A web server should return an HTTP 404 (Not Found) response when a requested resource does not exist. Sometimes, however, web servers are erroneously configured to return an HTTP 200 (OK) response along with a helpful HTML error page in such cases. This will cause a ServiceConfigurationError to be thrown when this class attempts to parse the HTML page as a provider-configuration file. The best solution to this problem is to fix the misconfigured web server to return the correct response code (HTTP 404) along with the HTML error page.
@CallerSensitive
public static <S> ServiceLoader<S> load(Class<S> service,
                                            ClassLoader loader){
  return new ServiceLoader<>(Reflection.getCallerClass(), service, loader);
}

        我们只需要传入class,使用Iterator去遍历就能拿到service所有的实现实例。

package com.bing.sh.utils;

import com.bing.sh.aop.proxy.ProxyFactory;

import java.util.Iterator;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.function.Supplier;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/19 0019 14:26
 */
public class ServiceLoaderUtil {


    public static <T> T loadService(Class<T> clazz, Supplier<? extends T> supplier) {
        final Iterator<T> iterator = load(clazz).iterator();
        while (iterator.hasNext()) {
            try {
                return iterator.next();
            } catch (ServiceConfigurationError e) {
                // ignore
            }
        }
        // 如果没有那么默认注入一个
        return supplier.get();
    }

    public static <T> ServiceLoader<T> load(Class<T> clazz) {
        return load(clazz, null);
    }


    public static <T> ServiceLoader<T> load(Class<T> clazz, ClassLoader classLoader) {
        return ServiceLoader.load(clazz, ObjectUtil.defaultIfNull(classLoader, ClassLoaderUtil::getClassLoader));
    }
}

四、默认使用Cglib创建代理对象

        Cglib动态代理不需要目标对象实现接口即可创建代理对象,相比于JDK动态代理稍微更简洁些。

        如果没有配置services,那么使用CglibProxcFactory:

    private static ProxyFactory createFactory() {
        return ServiceLoaderUtil.loadService(ProxyFactory.class, () -> {
            try {
                return ClassUtil.loadClass(CglibProxyFactory.class);
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        });
    }

五、代理核心实现 

        我们只需要在Interceptor类里实现代理方法的befor、after、throwException的调用即可。

package com.bing.sh.aop.interceptor;

import com.bing.sh.aop.aspect.Aspect;
import com.bing.sh.utils.ClassUtil;
import com.bing.sh.utils.ReflectUtils;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @Desc:  代理的对象不需要实现额外的接口即可生成一个代理对象,也是默认的代理方式
 * @Author: bingbing
 * @Date: 2022/4/18 0018 23:32
 */
public class CglibInterceptor implements MethodInterceptor, Serializable {
    private static final long serialVersionUID = 1L;

    private final Object target;

    private final Aspect aspect;

    public CglibInterceptor(Object target, Aspect aspect) {
        this.target = target;
        this.aspect = aspect;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        final Object target = this.target;
        Object result = null;

        if (aspect.before(target, method, args)) {
            try {
                ReflectUtils.setAccessible(method);
                result = method.invoke(ClassUtil.isStatic(method) ? null : target, args);
            } catch (InvocationTargetException e) {
                // 捕获业务代码导致的异常
                if (aspect.throwException(target, method, args, e.getTargetException())) {
                    throw e;
                }
            }
        }

        if (aspect.after(target, method, args, result)) {
            return result;
        }

        return null;
    }
}

六、ProxyUtil 

        使用Class<? extends Aspect>表示参数的上限类型为Aspect, 可传入Aspect接口的子类。

package com.bing.sh.aop.proxy;

import com.bing.sh.aop.aspect.Aspect;
import com.bing.sh.aop.interceptor.JDKInterceptor;

import java.lang.reflect.Proxy;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/19 0019 19:48
 */
public class ProxyUtil {

    public static <T> T Proxy(T target, Class<? extends Aspect> aspect) {
        return ProxyFactory.createProxy(target, aspect);
    }

    public static <T> T newProxyInstance(ClassLoader classLoader, JDKInterceptor interceptor, Class<?>[] interfaces) {
        return (T) Proxy.newProxyInstance(classLoader, interfaces, interceptor);
    }
}

七、自定义切面类

        实现Aspect接口,所有方法均返回true。

package com.bing.sh.aop.aspect;

import java.lang.reflect.Method;

/**
 * @Desc: 继承此类并重新该方法就能创建某个类的代理对象
 * @Author: bingbing
 * @Date: 2022/4/19 0019 10:59
 */
public class SimpleAspect implements Aspect {
    @Override
    public boolean before(Object target, Method method, Object[] args) {
        return true;
    }

    @Override
    public boolean after(Object target, Method method, Object[] args, Object returnValue) {
        return true;
    }

    @Override
    public boolean throwException(Object target, Method method, Object[] args, Throwable throwable) {
        return true;
    }
}

        我们只需要继承SimpleAspect类就能创建一个切面类:

public   class MyAspect extends SimpleAspect {


        @Override
        public boolean before(Object target, Method method, Object[] args) {
            System.out.println("先开机...");
            return true;
        }

        @Override
        public boolean after(Object target, Method method, Object[] args, Object returnValue) {
            System.out.println("挂掉...");
            return true;
        }
    }

 测试:

package com.bing.sh.aop;

import com.bing.sh.aop.aspect.SimpleAspect;
import com.bing.sh.aop.proxy.ProxyFactory;
import com.bing.sh.aop.proxy.ProxyUtil;
import org.junit.Before;
import org.junit.Test;

import java.lang.reflect.Method;

/**
 * @Desc:
 * @Author: bingbing
 * @Date: 2022/4/19 0019 9:41
 */
public class AopTests {

    // 如果是内部类那么必须为静态内部类//java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
    static class FixPhone {

        public void call() {
            System.out.println("fixphone打电话...");
        }

        public void sendMessage() {
            System.out.println("发送短信...");
        }
    }


    static class MobilePhone implements Phone {

        public MobilePhone() {
            //java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
        }

        @Override
        public void call() {
            System.out.println("mobile打电话...");
        }

        @Override
        public void sendMessage() {
            System.out.println("mobile发送短信...");
        }
    }


    interface Phone {
        void call();

        void sendMessage();
    }

   public class MyAspect extends SimpleAspect {


        @Override
        public boolean before(Object target, Method method, Object[] args) {
            System.out.println("先开机...");
            return true;
        }

        @Override
        public boolean after(Object target, Method method, Object[] args, Object returnValue) {
            System.out.println("挂掉...");
            return true;
        }
    }


    public class AnimalAspect extends SimpleAspect {


        @Override
        public boolean before(Object target, Method method, Object[] args) {
            System.out.println("先起床...");
            return true;
        }

        @Override
        public boolean after(Object target, Method method, Object[] args, Object returnValue) {
            System.out.println("后睡觉...");
            return true;
        }
    }


    @Test
    public void testAopByAutoCgLib() {
        FixPhone fixPhone = ProxyUtil.Proxy(new FixPhone(), MyAspect.class);
        fixPhone.call();

        MobilePhone mobilePhone = ProxyUtil.Proxy(new MobilePhone(), MyAspect.class);
        mobilePhone.call();

        Dog dog = ProxyUtil.Proxy(new Dog(), AnimalAspect.class);
        dog.eat();
    }
}

Hutool参考文档

简单实现ioc、aop事务demo
10-19
简单实现ioc、aop事务demo,实现事务回滚,使用到了,工厂模式,动态代理
Toy-Ioc-Aop:自定义Ioc和Aop得实现
04-04
玩具车 自定义Ioc和Aop得实现 IOC,基本思路就是,通过beanfactory读取指定得beans.xml配置文件,提前实例化相关得类进行存储,然后循环类里面得属性依赖,细长的主动...AOP,基本思路就是,通过动态代理方式实现
Aop
Trygoto的博客
02-25 911
简单Aop,展示aop设计思路和基础原理 提示:本文章适合有一定java反射基础的程序员,博主还是个新超新,欢迎指正!!!本文是参考Java 编程逻辑一书… 文章目录简单Aop,展示aop设计思路和基础原理Aop 简介:一、Aop 的基础原理是动态代理动态代理又有哪些呢?二、Aop实例1.创建自定义注解2.创建切面类 Aop 简介: 简介百度一大堆,这里简单说下博主自己的理解,Aop其实就是用来解决成品系统中添加辅助功能的一种方式。当你的系统所有功能都完成了,你调试 的时候发现没有
Spring框架---AOP实现
最新发布
汤键的博客
06-18 698
Spring框架---AOP实现
第七篇 - Aop(面向切面编程)
蓝星花
10-21 931
Github源码下载地址:https://github.com/chenxingxing6/sourcecode/tree/master/code-springaop 一、前言 AOP为Aspect Oriented Programming的缩,意为:面向切面编程,通过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Sprin...
Cglib动态代理
Damon_CCH的博客
09-23 210
package cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.junit.Test; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public clas.
Java 动态代理:Java Proxy 和 CGLIB
www.wuxianjie.net
05-30 369
Java 动态代理:Java Proxy 和 CGLIB静态代理JDK 原生动态代理(Java Proxy)CGLIB 动态代理Java Proxy vs CGLIB 如果我们想要编简洁、易维护的 Java 代码,那么掌握动态代理是其中必不可少的一个技术。 想必大家都用过 Spring 框架,因此动态代理对于我们来说也不会太陌生。因为 Spring 框架中大量使用了动态代理,比如 Spring ...
两万字吐血总结,代理模式及实现动态代理aop原理,基于jdk动态代理
12-22
代理模式及实现动态代理aop原理)一、代理模式1. 定义2. 示例(1)静态代理(2)动态代理3...代理模式(Proxy Pattern) 是一个使用频率非常高的设计模式,其定义如下: Provide a surrogate or placeholder for an
Java实现AOP功能的封装与配置的小框架实例代码
08-28
主要介绍了Java实现AOP功能的封装与配置的小框架实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
MySpring案例
12-26
模仿Spring实现自己的简单的框架。 关联博文:https://blog.csdn.net/qq_40977710/article/details/111659599 代码内容主要来自中国大学MOOC平台上陈良育老师讲的Java核心编程高阶实战案例:MySpring。
SpringAop底层源码剖析详解
09-24
本次课程将带领大家深入剖析SPring的AOP原理,让大家了解底源码底层是怎么样允许的,带领大家SpringAOP底层调用链进行实战练习,详细看完本次课程的同学都会对AOP的理解度达到新的程度。还是那句老话,对视频里面讲解的知识点要是有不懂的记得联系我,私信我都行的
JDK动态代理及CGLIB代理
qq_37578465的博客
09-19 711
JDK动态代理及CGLIB代理指的是什么?有什么作用?分别在什么时候调用? 他们之间又有什么区别? 1.什么是JDK动态代理? 大家在使用spring的时候,例如当我们在Dao层的时候如果只Dao接口,而不实现类,这时就是通过我们的jdk自带的动态代理来实现的,它底层通过反射来创建我们的实现类,以及反射实现所有的方法.($Proxy). 2.什么是CGLIB动态代理? CGLIB动态代理是基...
一个Spring框架(不含AOP
weixin_38520617的博客
12-09 229
spring 分三个阶段: 1.配置阶段: web.xml配置 servlet初始化 2.初始化阶段: 加载配置文件 ioc容器初始化 扫描相关的类 类实例化,并注入ioc容器 将url路径和相关method进行映射关联 3运行阶段 dopost作为入口 根据url找到method,通过反射去运行method; response.getWriter(().wirte(...
自己一个AOP动态代理框架(2)
Fujie1997的博客
06-02 549
之前实现的自己一个AOP动态代理框架(1)只能根据控制器,业务层,DAO层等等注解的形式来进行切面,这里仿Spring,支持AspectJ的表达式进行定位类方法资源,然后进行代理。 集成AspectJ的语法树,即复用AspecJ的对资源的定位功能。也就是说可以使用 execution(* com.fuyouj.service..*.*(..))这样的表达式。 AspectJ简介 提供了完整的AOP实现。 定义了切面语法和切面语法的解析。 Spring支持方法级别的织入(满足80%的需求了),Aspe.
Cglib动态代理模式实现
x329357842的博客
05-15 1万+
cglib代理与JDK中的代理比较: JDK动态代理: 只能代理实现了接口的类 没有实现接口的类不能实现JDK动态代理。 Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。 我们要使用cglib代理必须引入 cglib的jar包//轮船类 package com.zs.spring.demo1;public class Ship {
Java SPI META-INF/services 详解
热门推荐
geforce
05-28 1万+
1.什么是SPI SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的接口,它可以用来启用框架扩展和替换组件。SPI的作用就是为这些被扩展的API寻找服务实现。 2.SPI和API的使用场景 API (Application Programming Interface)在大多数情况下,都是实现方制定接口并完成对接口的实现,调用方仅仅依赖接口调用,且无权选择不同实现。从使用人员上来说,API 直接被应用开发人员使用。 ...
JDK动态代理
SDAUguo的博客
12-05 633
JDK动态代理实现之前,我们先看一下我们平时是怎么用的。 举个例子,你想找对象,但是没有时间,只能委托媒婆去帮你找,代码实现如下: // 一个统一接口 public interface Person { // 找对象接口 void findLove(); } // 客户类 public class Customer implements Person{ @Override public void findLove() { System.ou
10、对于JDK动态代理的一个简单封装ProxyUtil的使用
Learning
07-14 1366
1、对于JDK的动态代理,进行了一个简单的封装。以便于操作起来更简单。 2、IUserDao.java接口的定义 public interface IUserDao { public void add(); public void delete(); } 3、UserDao.java的实现 public class UserDao implements IUserDao {
如何一个AOP简单框架
03-30
下面是一个简单的AOP框架的步骤: 1. 定义注解 定义一个自定义注解,用于标注需要增强的方法。例如: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • Java中的List与Set转换 80733
  • @Transactional注解详细使用 66060
  • Eureka服务发现注册详解 36577
  • 用nginx部署前端项目 27559
  • mysql计算2个日期的月份差和天数差 27058

分类专栏

  • english banner
  • Conversation 1篇
  • TV episodes 1篇
  • funny daily life 11篇
  • Selected Short Stories 7篇
  • algorithm and structure 14篇
  • Leetcode competition 4篇
  • recursive algorithm 5篇
  • one more point algorithm 1篇
  • multiple thead algorithm 2篇
  • some sort algorithm 4篇
  • String algorithm 6篇
  • several loop problem 1篇
  • tree algorithm 5篇
  • chain algorithm 10篇
  • Java SDK Toolkits
  • data structure 1篇
  • cache 1篇
  • proxy 3篇
  • Class and ClassLoader
  • cloud 2篇
  • docker 12篇
  • kubernetes 6篇
  • component basis on spring 15篇
  • Redis 5篇
  • elasticsearch 3篇
  • message queue 6篇
  • distributed schedule XxlJob 5篇
  • EasyExcel 2篇
  • linux notes 15篇
  • source code
  • Spring source code 6篇
  • mybatis source code 1篇
  • dubbo source code 11篇
  • rocketmq source code 5篇
  • Sentinel source code
  • Nacos source code 1篇
  • Tomcat source code 1篇
  • net programming 3篇
  • JUC 15篇
  • micro service architecture 42篇
  • micro service management 1篇
  • java notes 34篇
  • Spring notes 7篇
  • design partten 14篇
  • for interview 13篇
  • python-django-tornado-flask 60篇
  • db(mysql、mybatis、mongodb) 17篇
  • vue-react-angular-web 9篇

最新评论

  • Mysql 5.7 免安装版windows安装完整教程

    static326: 初始化报错的话 2024-05-21T03:02:21.983203Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting. 2024-05-21T03:02:21.984368Z 0 [ERROR] Aborting 把my.ini文件放到bin目录下

  • django死锁问题: Lock wait timeout exceeded; try restarting transaction 怎么解决?

    m0_73554618: 大佬您好,这个解决的方法比较被动,有没有能够及时处理并解决这个问题的方法呢?

  • Spring boot 使用QRCodeWriter 制作二维码

    令人头秃的bug: 这个能扫码看视频或者文档吗?

  • 基于tornado实现websocket通信

    七月听雪: 加了啊 你的代码不是有吗

  • django死锁问题: Lock wait timeout exceeded; try restarting transaction 怎么解决?

    Chaos_Taiji: 大佬,我也发生了你说的这种情况,但是我看了这个INNODB_TRX 表,我的这个表是空的。求教怎么解决?

大家在看

  • 数组大扫雷行动:JavaScript中的高效移除指定元素 314
  • 证照之星!
  • Telnet发邮件的功能如何实现?有哪些限制?
  • 工业互联网基本概念及关键技术(295页PPT) 569
  • Python自动化发送邮件如何实现?怎么配置?

最新文章

  • Angular(二) Understanding Dependency Injection for angular
  • General Q&A for angular application
  • The coming up production issues
2023年31篇
2022年44篇
2021年104篇
2020年153篇
2019年22篇
2018年2篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦钢铁侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司宁德网站建设设计哪家好遂宁优秀网站设计哪家好广安网站优化公司内江如何制作网站推荐德阳百度网站优化排名哪家好荷坳网站排名优化鹤壁营销型网站建设价格厦门关键词按天收费推荐龙岩设计公司网站哪家好醴陵百姓网标王公司西乡阿里店铺托管哪家好运城企业网站设计价格沈阳关键词按天计费公司南平企业网站设计哪家好松岗网站改版报价巴中百度网站优化排名哪家好日照推广网站价格同乐百姓网标王推广价格黄南网站优化按天收费哪家好三明百姓网标王多少钱嘉兴网站优化按天计费海西SEO按天收费价格中卫关键词按天收费多少钱塔城关键词排名包年推广多少钱吉林外贸网站制作哪家好朝阳外贸网站设计哪家好丽水网站关键词优化报价红河seo网站推广推荐广州网络推广报价石家庄网站优化推广哪家好歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化