当前位置: 首页 > news >正文

好发网站建设网站搭建规划模板

好发网站建设,网站搭建规划模板,中国查公司的网站,wordpress大不了文章目录 1. 背景2. JDK动态代理2.1 定义和演示2.2 不同方法分别代理2.3 熔断限流和日志监控 3. CGLIB动态代理3.1 定义和演示3.2 不同方法分别代理#xff08;对比JDK动态代理写法#xff09;3.3 熔断限流和日志监控#xff08;对比JDK动态代理写法#xff09; 4. 动态代理… 文章目录 1. 背景2. JDK动态代理2.1 定义和演示2.2 不同方法分别代理2.3 熔断限流和日志监控 3. CGLIB动态代理3.1 定义和演示3.2 不同方法分别代理对比JDK动态代理写法3.3 熔断限流和日志监控对比JDK动态代理写法 4. 动态代理图示5. JDK动态代理 VS CGLIB动态代理对比6. 动态代理的实际应用场景 1. 背景 动态代理是一种强大的设计模式它允许开发者在运行时创建代理对象用于拦截对真实对象的方法调用。这种技术在实现面向切面编程AOP、事务管理、权限控制等功能时特别有用因为它可以在不修改原有代码结构的前提下为程序动态地注入额外的逻辑。 2. JDK动态代理 2.1 定义和演示 JDK动态代理是Java语言提供的一种基于接口的代理机制允许开发者在运行时动态地创建代理对象而无需为每个类编写具体的代理实现。 这种机制主要通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口实现。下面是JDK动态代理的核心要点和如何使用它们的概述。 使用步骤 定义接口首先定义一个或多个接口代理对象将实现这些接口。 实现接口创建一个类它实现上述接口提供具体的实现逻辑。 创建 InvocationHandler 实现定义一个 InvocationHandler 的实现这个实现中的 invoke 方法可以包含自定义逻辑。 创建代理对象使用 Proxy.newProxyInstance 方法传入目标对象的类加载器、需要代理的接口数组以及 InvocationHandler 的实现来创建一个实现了指定接口的代理对象。 用简单的例子来说明这个过程全部代码如下 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;interface HelloWorld {void sayHello(); }class HelloWorldImpl implements HelloWorld {public void sayHello() {System.out.println(Hello world!);} }public class DemoApplication {public static void main(String[] args) {HelloWorldImpl realObject new HelloWorldImpl();HelloWorld proxyInstance (HelloWorld) Proxy.newProxyInstance(HelloWorldImpl.class.getClassLoader(), // 使用目标类的类加载器new Class[]{HelloWorld.class}, // 代理类需要实现的接口列表new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在调用目标方法前可以插入自定义逻辑System.out.println(Before method call);// 调用目标对象的方法Object result method.invoke(realObject, args);// 在调用目标方法后可以插入自定义逻辑System.out.println(After method call);return result;}});proxyInstance.sayHello();} }运行结果如下 InvocationHandler 是动态代理的核心接口之一当我们使用动态代理模式创建代理对象时任何对代理对象的方法调用都会被转发到一个实现了 InvocationHandler 接口的实例的 invoke 方法上。 我们经常看到InvocationHandler 动态代理的匿名内部类这会在代理对象的相应方法被调用时执行。具体地说每当对代理对象执行方法调用时调用的方法不会直接执行而是转发到实现了InvocationHandler 的 invoke 方法上。在这个 invoke 方法内部我们可以定义拦截逻辑、调用原始对象的方法、修改返回值等操作。 在这个例子中当调用 proxyInstance.sayHello() 方法时实际上执行的是 InvocationHandler 的匿名内部类中的 invoke 方法。这个方法中我们可以在调用实际对象的 sayHello 方法前后添加自定义逻辑比如这里的打印消息。这就是动态代理和 InvocationHandler 的工作原理。 我们来看关键的一句代码 Object result method.invoke(realObject, args);在Java的动态代理中method.invoke(realObject, args) 这句代码扮演着核心的角色因为它实现了代理对象方法调用的转发机制。下面分别解释一下这行代码的两个主要部分method.invoke() 方法和 args 参数。 method.invoke(realObject, args) 作用这行代码的作用是调用目标对象realObject的具体方法。在动态代理的上下文中invoke 方法是在代理实例上调用方法时被自动调用的。通过这种方式可以在实际的方法执行前后加入自定义的逻辑比如日志记录、权限检查等。 methodmethod 是一个 java.lang.reflect.Method 类的实例代表了正在被调用的方法。在 invoke 方法中这个对象用来标识代理对象上被调用的具体方法。 注意如果尝试直接在invoke方法内部使用method.invoke(proxy, args)调用代理对象的方法而不是调用原始目标对象的方法则会导致无限循环。这是因为调用proxy实例上的方法会再次被代理拦截从而无限调用invoke方法传参可别传错了。 invokeMethod 类的 invoke 方法用于执行指定方法。第一个参数是指明方法应该在哪个对象上调用在这个例子中是 realObject后续的参数 args 是调用方法时传递的参数。 args 定义args 是一个对象数组包含了调用代理方法时传递给方法的参数值。如果被调用的方法没有参数args 将会是 null 或者空数组。 作用args 允许在 invoke 方法内部传递参数给实际要执行的方法。这意味着可以在动态代理中不仅控制是否调用某个方法还可以修改调用该方法时使用的参数。 2.2 不同方法分别代理 我们继续通过扩展 HelloWorld 接口来包含多个方法并通过JDK动态代理演示权限控制和功能开关操作的一种实现方式 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;interface HelloWorld {void sayHello();void sayGoodbye(); }class HelloWorldImpl implements HelloWorld {public void sayHello() {System.out.println(Hello world!);}public void sayGoodbye() {System.out.println(Goodbye world!);} }public class DemoApplication {public static void main(String[] args) {HelloWorld realObject new HelloWorldImpl();HelloWorld proxyInstance (HelloWorld) Proxy.newProxyInstance(HelloWorldImpl.class.getClassLoader(),new Class[]{HelloWorld.class},new InvocationHandler() {// 添加一个简单的权限控制演示private boolean accessAllowed true;// 简单的功能开关private boolean goodbyeFunctionEnabled true;Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 权限控制if (!accessAllowed) {System.out.println(Access denied);return null; // 在实际场景中可以抛出一个异常}// 功能开关if (method.getName().equals(sayGoodbye) !goodbyeFunctionEnabled) {System.out.println(Goodbye function is disabled);return null;}// 方法执行前的通用逻辑System.out.println(Before method: method.getName());// 执行方法Object result method.invoke(realObject, args);// 方法执行后的通用逻辑System.out.println(After method: method.getName());return result;}});// 正常执行proxyInstance.sayHello();// 可以根据goodbyeFunctionEnabled变量决定是否执行proxyInstance.sayGoodbye();} }运行如下 如果accessAllowed 变量为false 如果goodbyeFunctionEnabled 变量为false 在这个例子中 权限控制通过检查 accessAllowed 变量我们可以模拟简单的权限控制。如果没有权限可以直接返回或抛出异常避免执行方法。 功能开关通过检查方法名称和 goodbyeFunctionEnabled 变量我们可以控制 sayGoodbye 方法是否被执行。这可以用来根据配置启用或禁用特定功能。 这个例子展示了JDK动态代理在实际应用中如何进行方法级别的细粒度控制同时保持代码的灵活性和可维护性。通过动态代理我们可以在不修改原始类代码的情况下为对象动态地添加额外的行为。 2.3 熔断限流和日志监控 为了更全面地展示JDK动态代理的能力我们在先前的示例中添加熔断限流和日志监控的逻辑。这些是在高并发和分布式系统中常见的需求可以通过动态代理以非侵入式的方式实现。 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong;interface HelloWorld {void sayHello(); }class HelloWorldImpl implements HelloWorld {public void sayHello() {System.out.println(Hello world!);} }public class DemoApplication {public static void main(String[] args) {HelloWorld realObject new HelloWorldImpl();HelloWorld proxyInstance (HelloWorld) Proxy.newProxyInstance(HelloWorldImpl.class.getClassLoader(),new Class[]{HelloWorld.class},new AdvancedInvocationHandler(realObject));// 模拟多次调用以观察限流和熔断效果for (int i 0; i 10; i) {proxyInstance.sayHello();}}static class AdvancedInvocationHandler implements InvocationHandler {private final Object target;private AtomicInteger requestCount new AtomicInteger(0);private AtomicLong lastTimestamp new AtomicLong(System.currentTimeMillis());private volatile boolean circuitBreakerOpen false;private final long cooldownPeriod 10000; // 冷却时间10秒public AdvancedInvocationHandler(Object target) {this.target target;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long now System.currentTimeMillis();// 检查熔断器是否应该被重置if (circuitBreakerOpen (now - lastTimestamp.get() cooldownPeriod)) {circuitBreakerOpen false; // 重置熔断器requestCount.set(0); // 重置请求计数System.out.println(Circuit breaker has been reset.);}// 熔断检查if (circuitBreakerOpen) {System.out.println(Circuit breaker is open. Blocking method execution for: method.getName());return null; // 在实际场景中可以返回一个兜底的响应或抛出异常}// 限流检查if (requestCount.incrementAndGet() 5) {if (now - lastTimestamp.get() cooldownPeriod) { // 10秒内超过5次请求触发熔断circuitBreakerOpen true;lastTimestamp.set(now); // 更新时间戳System.out.println(Too many requests. Opening circuit breaker.);return null; // 触发熔断时的处理} else {// 重置计数器和时间戳requestCount.set(0);lastTimestamp.set(now);}}// 执行实际方法Object result method.invoke(target, args);// 方法执行后的逻辑System.out.println(Executed method: method.getName());return result;}} }在这个扩展示例中我们实现了 熔断机制通过一个简单的计数器和时间戳来模拟。如果在10秒内对任一方法的调用次数超过5次我们就打开熔断器阻止进一步的方法调用。在实际应用中熔断逻辑可能更加复杂可能包括错误率的检查、调用延迟的监控等。 限流这里使用的限流策略很简单通过计数和时间戳来判断是否在短时间内请求过多。在更复杂的场景中可以使用令牌桶或漏桶算法等更高级的限流策略。 日志监控在方法调用前后打印日志这对于监控系统的行为和性能是非常有用的。在实际项目中这些日志可以集成到日志管理系统中用于问题诊断和性能分析。 通过在 invoke 方法中加入这些逻辑我们能够在不修改原有业务代码的情况下为系统添加复杂的控制和监控功能。如果到达流量阈值或系统处于熔断状态可以阻止对后端服务的进一步调用直接返回一个默认值或错误响应避免系统过载。 3. CGLIB动态代理 CGLIBCode Generation Library是一个强大的高性能代码生成库它在运行时动态生成新的类。与JDK动态代理不同CGLIB能够代理那些没有实现接口的类。这使得CGLIB成为那些因为设计限制或其他原因不能使用接口的场景的理想选择。 3.1 定义和演示 工作原理 CGLIB通过继承目标类并在运行时生成子类来实现动态代理。代理类覆盖了目标类的非final方法并在调用方法前后提供了注入自定义逻辑的能力。这种方法的一个关键优势是它不需要目标对象实现任何接口。 使用CGLIB的步骤 添加CGLIB依赖首先需要在项目中添加CGLIB库的依赖。 如果使用Maven可以添加如下依赖到pom.xml中 dependencygroupIdcglib/groupIdartifactIdcglib/artifactIdversion3.3.0/version !-- 目前最新的版本 -- /dependency创建MethodInterceptor实现MethodInterceptor接口这是CGLIB提供的回调类型用于定义方法调用的拦截逻辑。 生成代理对象使用Enhancer类来创建代理对象。Enhancer是CGLIB中用于生成新类的类。 改造一下1.1节的例子可以对比看看全部示例代码如下 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;class HelloWorld {public void sayHello() {System.out.println(Hello world!);} }public class DemoApplication {public static void main(String[] args) {Enhancer enhancer new Enhancer();// 设置需要代理的类enhancer.setSuperclass(HelloWorld.class);enhancer.setCallback(new MethodInterceptor() {Overridepublic Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(Before method call);Object result proxy.invokeSuper(obj, args); // 调用父类的方法System.out.println(After method call);return result;}});HelloWorld proxy (HelloWorld) enhancer.create(); // 创建代理对象proxy.sayHello(); // 通过代理对象调用方法} }运行结果如下 CGLIB vs JDK动态代理 接口要求JDK动态代理只能代理实现了接口的对象而CGLIB能够直接代理类。性能CGLIB在生成代理对象时通常比JDK动态代理要慢因为它需要动态生成新的类。但在调用代理方法时CGLIB通常会提供更好的性能。方法限制CGLIB不能代理final方法因为它们不能被子类覆盖。 CGLIB是一个强大的工具特别适用于需要代理没有实现接口的类的场景。然而选择JDK动态代理还是CGLIB主要取决于具体的应用场景和性能要求。 注意在CGLIB中如果使用MethodProxy.invoke(obj, args) 而不是MethodProxy.invokeSuper(obj, args)并且obj是代理实例本身CGLIB通过Enhancer创建的代理对象而不是原始的被代理的目标对象就会导致无限循环。invoke方法实际上是尝试在传递的对象上调用方法如果该对象是代理对象则调用会再次被拦截造成无限循环。 在JDK动态代理中确保调用method.invoke时使用的是目标对象而不是代理对象。 在CGLIB代理中使用MethodProxy.invokeSuper而不是MethodProxy.invoke来调用被代理的方法以避免无限循环。 3.2 不同方法分别代理对比JDK动态代理写法 我们改写1.2节的例子 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;class HelloWorldImpl {public void sayHello() {System.out.println(Hello world!);}public void sayGoodbye() {System.out.println(Goodbye world!);} }public class DemoApplication {public static void main(String[] args) {Enhancer enhancer new Enhancer();enhancer.setSuperclass(HelloWorldImpl.class); // 设置被代理的类enhancer.setCallback(new MethodInterceptor() {// 添加一个简单的权限控制演示private boolean accessAllowed true;// 简单的功能开关private boolean goodbyeFunctionEnabled true;Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {// 权限控制if (!accessAllowed) {System.out.println(Access denied);return null; // 在实际场景中可以抛出一个异常}// 功能开关if (method.getName().equals(sayGoodbye) !goodbyeFunctionEnabled) {System.out.println(Goodbye function is disabled);return null;}// 方法执行前的通用逻辑System.out.println(Before method: method.getName());// 执行方法Object result proxy.invokeSuper(obj, args);// 方法执行后的通用逻辑System.out.println(After method: method.getName());return result;}});HelloWorldImpl proxyInstance (HelloWorldImpl) enhancer.create(); // 创建代理对象proxyInstance.sayHello(); // 正常执行proxyInstance.sayGoodbye(); // 可以根据goodbyeFunctionEnabled变量决定是否执行} }运行结果如下 我们需要注意几点更改 因为CGLIB不是基于接口的代理而是通过生成目标类的子类来实现代理所以我们不再需要接口HelloWorld。 我们将使用Enhancer类来创建代理实例并提供一个MethodInterceptor来处理方法调用。 3.3 熔断限流和日志监控对比JDK动态代理写法 我们改写1.3节的例子 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong;class HelloWorld {void sayHello() {System.out.println(Hello world!);} }public class DemoApplication {public static void main(String[] args) {HelloWorld realObject new HelloWorld();HelloWorld proxyInstance (HelloWorld) createProxy(realObject);// 模拟多次调用以观察限流和熔断效果for (int i 0; i 10; i) {proxyInstance.sayHello();}}public static Object createProxy(final Object realObject) {Enhancer enhancer new Enhancer();enhancer.setSuperclass(HelloWorld.class);enhancer.setCallback(new AdvancedMethodInterceptor(realObject));return enhancer.create();}static class AdvancedMethodInterceptor implements MethodInterceptor {private final Object target;private final AtomicInteger requestCount new AtomicInteger(0);private final AtomicLong lastTimestamp new AtomicLong(System.currentTimeMillis());private volatile boolean circuitBreakerOpen false;private final long cooldownPeriod 10000; // 冷却时间10秒public AdvancedMethodInterceptor(Object target) {this.target target;}Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {long now System.currentTimeMillis();// 检查熔断器是否应该被重置if (circuitBreakerOpen (now - lastTimestamp.get() cooldownPeriod)) {circuitBreakerOpen false; // 重置熔断器requestCount.set(0); // 重置请求计数System.out.println(Circuit breaker has been reset.);}// 熔断检查if (circuitBreakerOpen) {System.out.println(Circuit breaker is open. Blocking method execution for: method.getName());return null; // 在实际场景中可以返回一个兜底的响应或抛出异常}// 限流检查if (requestCount.incrementAndGet() 5) {if (now - lastTimestamp.get() cooldownPeriod) { // 10秒内超过5次请求触发熔断circuitBreakerOpen true;lastTimestamp.set(now); // 更新时间戳System.out.println(Too many requests. Opening circuit breaker.);return null; // 触发熔断时的处理} else {// 重置计数器和时间戳requestCount.set(0);lastTimestamp.set(now);}}// 执行实际方法Object result proxy.invokeSuper(obj, args); // 注意这里调用的是invokeSuper// 方法执行后的逻辑System.out.println(Executed method: method.getName());return result;}} }运行结果 在这个改写中我们使用CGLIB的Enhancer和MethodInterceptor来代替了JDK的Proxy和InvocationHandler。MethodInterceptor的intercept方法与InvocationHandler的invoke方法在概念上是相似的但它使用MethodProxy的invokeSuper方法来调用原始类的方法而不是使用反射。这允许CGLIB在运行时生成代理类的字节码而不是依赖于反射从而提高了性能。此外circuitBreakerOpen被声明为volatile是确保其在多线程环境中的可见性。 4. 动态代理图示 方法调用拦截 客户端通过代理对象调用方法此时方法调用被代理对象拦截。 转发给处理器或方法拦截器 代理对象将方法调用转发给一个特定的处理器这取决于所使用的代理类型。对于JDK动态代理这个处理器是InvocationHandler对于CGLIB代理是MethodInterceptor。 执行额外操作调用前 在实际执行目标对象的方法之前处理器有机会执行一些额外的操作例如日志记录、安全检查或事务管理等。 调用目标对象的方法 处理器在必要时直接调用目标对象的方法。在JDK动态代理中这通常通过反射实现而在CGLIB中可以通过MethodProxy.invokeSuper方法调用。 执行额外操作调用后 方法调用完成后处理器再次有机会执行额外操作比如修改返回值、记录执行时间或进行事务的提交或回滚。 返回给客户端 最终方法的返回值被通过代理对象返回给客户端。 5. JDK动态代理 VS CGLIB动态代理对比 JDK动态代理 JDK动态代理是Java自带的代理机制它直接使用反射API来调用方法。 优点 无需第三方依赖作为Java标准API的一部分使用JDK动态代理不需要添加额外的库或依赖。 接口导向强制使用接口进行代理这符合面向接口编程的原则有助于保持代码的清晰和灵活。 缺点 仅限接口只能代理实现了接口的类这在某些情况下限制了它的使用。 性能开销由于使用反射API进行方法调用可能会有一定的性能开销尤其是在大量调用时。 CGLIB动态代理 CGLIBCode Generation Library通过在运行时生成被代理对象的子类来实现代理。 优点 不需要接口可以代理没有实现任何接口的类这提供了更大的灵活性。 性能较好通常认为CGLIB的性能比JDK动态代理要好特别是在代理方法的调用上因为CGLIB使用了字节码生成技术减少了使用反射的需要。 缺点 第三方库需要添加CGLIB库作为项目依赖。 无法代理final方法由于CGLIB是通过生成子类的方式来代理的所以无法代理那些被声明为final的方法。 性能比较 调用速度CGLIB在代理方法调用方面通常比JDK动态代理更快。这是因为CGLIB通过直接操作字节码来生成新的类避免了反射带来的性能开销。 启动性能CGLIB在生成代理对象时可能会比JDK动态代理慢因为它需要在运行时生成新的字节码。如果代理对象在应用启动时就被创建这可能会略微影响启动时间。 选择建议 如果类已经实现了接口或者希望强制使用接口编程那么JDK动态代理是一个好选择。 如果需要代理没有实现接口的类或者对性能有较高的要求特别是在代理方法的调用上CGLIB可能是更好的选择。 在现代的Java应用中很多框架如Spring都提供了对这两种代理方式的透明支持并且可以根据实际情况自动选择使用哪一种。例如Spring AOP默认会使用JDK动态代理但如果遇到没有实现接口的类它会退回到CGLIB。 6. 动态代理的实际应用场景 面向切面编程AOP 问题解决在不改变原有业务逻辑代码的情况下为程序动态地添加额外的行为如日志记录、性能监测、事务管理等。 应用实例Spring AOP 使用动态代理为方法调用提供了声明式事务管理、安全性检查和日志记录等服务。根据目标对象是否实现接口Spring AOP可以选择使用JDK动态代理或CGLIB代理。 事务管理 问题解决自动化处理数据库事务的边界如开始、提交或回滚事务。 应用实例Spring框架中的声明式事务管理使用代理技术拦截那些被Transactional注解标记的类或方法确保方法执行在正确的事务管理下进行。 权限控制和安全性 问题解决在执行敏感操作之前自动检查用户权限确保只有拥有足够权限的用户才能执行某些操作。 应用实例企业应用中使用代理技术拦截用户的请求进行权限验证后才允许访问特定的服务或执行操作。 延迟加载 问题解决对象的某些属性可能加载成本较高通过代理技术可以在实际使用这些属性时才进行加载。 应用实例Hibernate和其他ORM框架使用代理技术实现了延迟加载懒加载以提高应用程序的性能和资源利用率。 服务接口调用的拦截和增强 问题解决对第三方库或已有服务进行包装添加额外的逻辑如缓存结果、参数校验等。 应用实例在微服务架构中可以使用代理技术对服务客户端进行增强实现如重试、熔断、限流等逻辑。 在现代框架中的应用 Spring框架Spring的AOP模块和事务管理广泛使用了动态代理技术。根据目标对象的类型是否实现接口Spring可以自动选择JDK动态代理或CGLIB代理。 HibernateHibernate使用动态代理技术实现懒加载代理实体类的关联对象在实际访问这些对象时才从数据库中加载它们的数据。 MyBatisMyBatis框架使用动态代理技术映射接口和SQL语句允许开发者通过接口直接与数据库交互而无需实现类。 欢迎一键三连~ 有问题请留言大家一起探讨学习 ----------------------Talk is cheap, show me the code-----------------------
http://www.yingshimen.cn/news/44779/

相关文章:

  • 移动网站怎么做网页设计实验报告实验方法
  • 中文域名做的网站有哪些制作灯笼的手工做法视频
  • 电商网站 建设价格推荐大气的网站
  • 做网站挣钱推荐大气的网站
  • 自建站是什么意思wordpress怎么添加菜单
  • 芜湖的公司长沙网站seo厂家
  • 团购网站 模板前端学到什么程度可以找到工作
  • 淘宝客如何做自己的网站网页小游戏入口
  • 什么做网站的公司好五大免费资源网站
  • 郑州新感觉会所网站哪里做的男人不知本网站 枉做
  • 网站建设及解决方案企业移动网站品牌
  • linux主网站设计创意的广告公司名字
  • 西班牙网站后缀wordpress主题cms
  • 个人网站怎么命名网站后台乱码
  • 菏泽专业网站开发公司邦派巴洛特网站是谁做的呀
  • 厦门网站建设公司名单个人备案网站名称
  • 小白如何建网站京东网站项目建设规划书
  • 做网站该注意哪些基本要素seo提升关键词排名
  • 建站哪个好一点山东省住房和城乡建设厅网站6
  • 贵州省城乡和建设厅网站网站建设的岗位是什么岗位
  • 招聘网站可以同时做两份简历吗推荐晚上用的网站
  • 服务器做网站数据库凡科网站代码怎么
  • 网站页面布局免费dedecms企业网站模板
  • 如何不让百度收录网站长沙制作网站设计多少钱
  • 珲春市建设局网站如何做类似千图网的网站
  • 网站静态化怎么做织梦医疗网站
  • 外贸工艺品网站建设wordpress实现h5翻页效果
  • 网站模板组件有质感的wordpress主题
  • 无代码网站开发平台有哪些河北省保定市唐县城乡建设网站
  • 网站建设北京海淀ui高级培训机构