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

Java 代理模式全解析:静态代理、JDK 动态代理与 CGLIB 代理实战

       在 Java 开发中,代理模式是一种常用的设计模式,核心思想是在不修改目标类代码的前提下,对目标方法进行增强(如日志记录、权限校验、事务管理等)。根据代理类的生成时机和实现方式,Java 中的代理技术主要分为三类:静态代理(编译期生成)、JDK 动态代理(运行时反射生成)、CGLIB 代理(运行时字节码生成)。

       本文将从原理、实战、对比三个维度,详细拆解这三种代理技术,帮你理清适用场景和核心差异,轻松应对实际开发中的代理需求(如 Spring AOP、框架插件开发等)。

一、代理模式核心概念

在正式讲解三种代理之前,先明确代理模式的核心角色:

  • 目标类(Target):被代理的原始类,包含核心业务逻辑;
  • 代理类(Proxy):包装目标类的类,负责在目标方法执行前后插入增强逻辑;
  • 增强逻辑(Advice):代理类的核心功能,如日志、事务、权限校验等;
  • 客户端(Client):调用方,通过代理类间接调用目标类的方法。

       代理模式的核心价值:解耦核心业务与增强逻辑,让目标类专注于业务本身,增强逻辑可复用、可切换。

二、静态代理:编译期的 “手动代理”

1. 原理剖析

       静态代理是最基础的代理实现,代理类由开发者手动编写,在编译期就生成.class文件。其核心逻辑是:

  1. 代理类与目标类实现相同的接口(或继承同一个父类),保证方法签名一致;
  2. 代理类内部持有目标类的实例(通过构造器注入);
  3. 代理类重写接口方法,在方法中先执行增强逻辑,再调用目标类的原始方法。

特点:无任何框架依赖,纯 Java 基础语法实现;但代码冗余度高,维护成本高。

2. 实战案例:静态代理实现日志增强

       需求:对用户服务(UserService)的添加、删除用户方法,添加 “执行前后日志” 的增强逻辑。

步骤 1:定义公共接口(规范目标类与代理类的方法)
/*** 用户服务接口:静态代理需基于接口(或父类)实现*/
public interface IUserService {void addUser(String username); // 添加用户void deleteUser(String username); // 删除用户String queryUser(String username); // 查询用户
}
步骤 2:实现目标类(核心业务逻辑)
/*** 目标类:用户服务核心实现*/
public class UserServiceImpl implements IUserService {@Overridepublic void addUser(String username) {// 核心业务:模拟添加用户System.out.println("【核心业务】添加用户成功:" + username);}@Overridepublic void deleteUser(String username) {// 核心业务:模拟删除用户System.out.println("【核心业务】删除用户成功:" + username);}@Overridepublic String queryUser(String username) {// 核心业务:模拟查询用户System.out.println("【核心业务】查询用户:" + username);return "用户信息:" + username + "(VIP)";}
}
步骤 3:手动编写代理类(注入目标类 + 增强逻辑)
/*** 静态代理类:手动编写,与目标类实现同一接口*/
public class UserServiceStaticProxy implements IUserService {// 持有目标类实例(通过构造器注入,解耦)private final IUserService target;// 构造器:传入目标类对象public UserServiceStaticProxy(IUserService target) {this.target = target;}@Overridepublic void addUser(String username) {// 增强逻辑:方法执行前System.out.println("【静态代理-日志】addUser 方法开始执行,参数:" + username);try {// 调用目标类的核心方法target.addUser(username);// 增强逻辑:方法执行成功后System.out.println("【静态代理-日志】addUser 方法执行成功");} catch (Exception e) {// 增强逻辑:异常处理System.out.println("【静态代理-日志】addUser 方法执行失败,异常:" + e.getMessage());} finally {// 增强逻辑:方法执行完毕(无论成功失败)System.out.println("【静态代理-日志】addUser 方法执行结束\n");}}@Overridepublic void deleteUser(String username) {// 与addUser逻辑一致,重复编写增强代码System.out.println("【静态代理-日志】deleteUser 方法开始执行,参数:" + username);try {target.deleteUser(username);System.out.println("【静态代理-日志】deleteUser 方法执行成功");} catch (Exception e) {System.out.println("【静态代理-日志】deleteUser 方法执行失败,异常:" + e.getMessage());} finally {System.out.println("【静态代理-日志】deleteUser 方法执行结束\n");}}@Overridepublic String queryUser(String username) {System.out.println("【静态代理-日志】queryUser 方法开始执行,参数:" + username);String result = null;try {result = target.queryUser(username);System.out.println("【静态代理-日志】queryUser 方法执行成功,结果:" + result);} catch (Exception e) {System.out.println("【静态代理-日志】queryUser 方法执行失败,异常:" + e.getMessage());} finally {System.out.println("【静态代理-日志】queryUser 方法执行结束\n");}return result;}
}
步骤 4:测试静态代理
public class StaticProxyTest {public static void main(String[] args) {// 1. 创建目标类实例IUserService target = new UserServiceImpl();// 2. 创建代理类实例(注入目标类)IUserService proxy = new UserServiceStaticProxy(target);// 3. 调用代理方法(间接执行目标方法+增强逻辑)proxy.addUser("张三");proxy.deleteUser("李四");proxy.queryUser("王五");}
}
执行结果
【静态代理-日志】addUser 方法开始执行,参数:张三
【核心业务】添加用户成功:张三
【静态代理-日志】addUser 方法执行成功
【静态代理-日志】addUser 方法执行结束【静态代理-日志】deleteUser 方法开始执行,参数:李四
【核心业务】删除用户成功:李四
【静态代理-日志】deleteUser 方法执行成功
【静态代理-日志】deleteUser 方法执行结束【静态代理-日志】queryUser 方法开始执行,参数:王五
【核心业务】查询用户:王五
【静态代理-日志】queryUser 方法执行成功,结果:用户信息:王五(VIP)
【静态代理-日志】queryUser 方法执行结束

3. 静态代理的优缺点

优点
  • 无依赖:纯 Java 基础实现,无需引入任何框架;
  • 性能好:编译期生成代理类,运行时无反射 / 字节码开销,执行效率高;
  • 逻辑直观:代理类代码手动编写,增强逻辑清晰可见,便于调试。
缺点
  • 代码冗余:目标类有 N 个方法,代理类就要写 N 个方法的增强逻辑,重复代码多;
  • 维护成本高:目标类新增 / 修改方法时,代理类需同步修改,扩展性差;
  • 灵活性低:代理类与目标类强绑定,无法动态切换目标类或增强逻辑。

4. 适用场景

  • 简单增强需求(如固定方法的日志、参数校验);
  • 目标类方法固定,不会频繁修改;
  • 不允许依赖第三方框架,追求极致运行性能。

三、JDK 动态代理:运行时的 “接口代理”

       JDK 动态代理是 Java 原生支持的动态代理技术,无需依赖第三方库,核心是通过java.lang.reflect包下的Proxy类和InvocationHandler接口,在运行时动态生成代理类(接口的实现类)。

1. 原理剖析

JDK 动态代理的核心逻辑的:

  1. 代理类由Proxy.newProxyInstance()方法在运行时动态生成,本质是目标接口的实现类
  2. 开发者需实现InvocationHandler接口(拦截器),将增强逻辑集中在invoke方法中;
  3. 客户端调用代理方法时,会被InvocationHandler拦截,执行增强逻辑后,通过反射调用目标类的原始方法。

关键限制:JDK 动态代理只能代理实现了接口的目标类(代理类是接口的实现类,无法继承目标类)。

2. 核心组件

  • Proxy:生成代理类的核心类,提供newProxyInstance()方法创建代理对象;
  • InvocationHandler:方法拦截器接口,需实现invoke方法(增强逻辑的核心);
    • invoke(Object proxy, Method method, Object[] args)
      • proxy:动态生成的代理对象;
      • method:被调用的目标方法;
      • args:方法参数;
      • 返回值:目标方法的执行结果。

3. 实战案例:JDK 动态代理实现日志 + 权限增强

需求:在静态代理的基础上,新增 “权限校验” 增强逻辑,且无需为每个方法重复编写增强代码。

步骤 1:复用目标类与接口(同静态代理的IUserServiceUserServiceImpl
步骤 2:实现InvocationHandler(集中管理增强逻辑)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** JDK动态代理拦截器:集中处理所有方法的增强逻辑*/
public class UserServiceInvocationHandler implements InvocationHandler {// 持有目标类实例private final Object target;// 构造器注入目标类public UserServiceInvocationHandler(Object target) {this.target = target;}/*** 拦截代理方法的执行:所有代理方法都会触发该方法*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {// 增强逻辑1:日志记录(方法执行前)System.out.println("【JDK动态代理-日志】" + method.getName() + " 方法开始执行,参数:" + (args != null ? args[0] : "无"));// 增强逻辑2:权限校验(仅对add/delete方法生效)if (method.getName().equals("addUser") || method.getName().equals("deleteUser")) {String username = (String) args[0];if (!"admin".equals(username)) {throw new RuntimeException("权限不足:仅admin可执行该操作");}System.out.println("【JDK动态代理-权限校验】用户 " + username + " 权限通过");}// 调用目标类的原始方法(通过反射)result = method.invoke(target, args);// 增强逻辑3:日志记录(方法执行后)System.out.println("【JDK动态代理-日志】" + method.getName() + " 方法执行成功,结果:" + result);} catch (Exception e) {// 增强逻辑4:异常处理System.out.println("【JDK动态代理-日志】" + method.getName() + " 方法执行失败,异常:" + e.getMessage());throw e; // 抛出异常,让客户端处理} finally {// 增强逻辑5:资源释放(示例)System.out.println("【JDK动态代理-资源】" + method.getName() + " 方法执行完毕,释放资源\n");}return result;}
}
步骤 3:通过Proxy生成代理对象并测试
import java.lang.reflect.Proxy;public class JdkDynamicProxyTest {public static void main(String[] args) {// 1. 创建目标类实例IUserService target = new UserServiceImpl();// 2. 创建拦截器实例(注入目标类)InvocationHandler handler = new UserServiceInvocationHandler(target);// 3. 动态生成代理对象IUserService proxy = (IUserService) Proxy.newProxyInstance(target.getClass().getClassLoader(), // 类加载器(与目标类一致)target.getClass().getInterfaces(),  // 目标类实现的接口(核心:JDK代理基于接口)handler                              // 拦截器(增强逻辑));// 4. 测试代理方法try {proxy.addUser("admin"); // 权限通过proxy.deleteUser("user"); // 权限不足,抛出异常} catch (Exception e) {// 捕获异常}proxy.queryUser("admin"); // 无权限校验}
}
执行结果
【JDK动态代理-日志】addUser 方法开始执行,参数:admin
【JDK动态代理-权限校验】用户 admin 权限通过
【核心业务】添加用户成功:admin
【JDK动态代理-日志】addUser 方法执行成功,结果:null
【JDK动态代理-资源】addUser 方法执行完毕,释放资源【JDK动态代理-日志】deleteUser 方法开始执行,参数:user
【JDK动态代理-权限校验】用户 user 权限不足
【JDK动态代理-日志】deleteUser 方法执行失败,异常:权限不足:仅admin可执行该操作
【JDK动态代理-资源】deleteUser 方法执行完毕,释放资源【JDK动态代理-日志】queryUser 方法开始执行,参数:admin
【核心业务】查询用户:admin
【JDK动态代理-日志】queryUser 方法执行成功,结果:用户信息:admin(VIP)
【JDK动态代理-资源】queryUser 方法执行完毕,释放资源

4. JDK 动态代理的优缺点

优点
  • 无依赖:JDK 原生支持,无需引入第三方库;
  • 代码简洁:增强逻辑集中在InvocationHandler,无需重复编写代理方法;
  • 灵活性高:可动态切换目标类(只需注入不同目标对象),支持接口扩展。
缺点
  • 只能代理接口:目标类必须实现接口,否则无法生成代理对象;
  • 性能一般:通过反射调用目标方法,JDK8 + 虽有优化,但仍有一定开销;
  • 无法代理私有方法:接口方法默认是 public,无法代理目标类的 private 方法。

5. 适用场景

  • 目标类实现了接口(如 Service 层接口);
  • 追求轻量代理,无需依赖第三方框架;
  • 增强逻辑需统一管理(如所有方法的日志、事务)。

四、CGLIB 代理:运行时的 “子类代理”

       CGLIB(Code Generation Library)是基于 ASM 字节码操作框架的动态代理库,核心能力是通过生成目标类的子类来实现代理,弥补了 JDK 动态代理只能代理接口的缺陷。广泛应用于 Spring、Hibernate 等框架。

1. 原理剖析

CGLIB 代理的核心逻辑:

  1. 通过 ASM 框架在运行时动态生成目标类的子类(代理类);
  2. 代理类重写目标类中所有非 final的方法(final 方法无法被继承重写);
  3. 开发者实现MethodInterceptor接口(方法拦截器),在intercept方法中定义增强逻辑;
  4. 客户端调用代理方法时,会被MethodInterceptor拦截,执行增强逻辑后,通过MethodProxy调用目标类的原始方法。

关键优势:可代理无接口的类,支持代理类的非 final 方法。

2. 核心组件

(1).Enhancer:CGLIB 的核心增强器,用于生成代理类,配置目标类、回调接口等;

(2).MethodInterceptor:方法拦截器接口,需实现intercept方法(增强逻辑核心);

 intercept(Object obj, Method method, Object[] args, MethodProxy proxy)

  • obj:代理对象(目标类的子类实例);
  • method:目标类的方法;
  • args:方法参数;
  • proxy:方法代理对象(推荐用于调用原始方法,性能优于反射);
  • 返回值:目标方法的执行结果。

(3).ASM:CGLIB 底层依赖的字节码操作框架,用于动态生成子类字节码。

3. 实战案例:CGLIB 代理实现日志 + 事务增强

需求:代理一个无接口的目标类,添加日志记录和事务管理(模拟)增强逻辑。

步骤 1:引入 CGLIB 依赖
<!-- Maven依赖 -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version> <!-- 最新稳定版 -->
</dependency>
步骤 2:定义无接口的目标类
/*** 无接口的目标类:CGLIB可直接代理类(无需接口)*/
public class OrderService {// 非final方法(可被代理)public void createOrder(String orderNo) {System.out.println("【核心业务】创建订单成功:" + orderNo);}// final方法(无法被代理)public final void cancelOrder(String orderNo) {System.out.println("【核心业务】取消订单成功:" + orderNo);}// 私有方法(无法被代理)private void logOrder(String orderNo) {System.out.println("【内部日志】订单操作:" + orderNo);}
}
步骤 3:实现MethodInterceptor(增强逻辑)
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;/*** CGLIB方法拦截器:定义增强逻辑*/
public class OrderServiceMethodInterceptor implements MethodInterceptor {/*** 拦截代理方法的执行*/@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {Object result = null;try {// 增强逻辑1:日志记录(方法执行前)System.out.println("【CGLIB代理-日志】" + method.getName() + " 方法开始执行,参数:" + args[0]);// 增强逻辑2:事务开始(模拟)System.out.println("【CGLIB代理-事务】开启事务");// 调用目标类的原始方法(两种方式)// 方式1:MethodProxy.invokeSuper(obj, args)(推荐,性能好,避免反射)result = proxy.invokeSuper(obj, args);// 方式2:Method.invoke(target, args)(需持有目标对象,反射调用,性能差)// result = method.invoke(target, args);// 增强逻辑3:事务提交(模拟)System.out.println("【CGLIB代理-事务】提交事务");// 增强逻辑4:日志记录(方法执行后)System.out.println("【CGLIB代理-日志】" + method.getName() + " 方法执行成功");} catch (Exception e) {// 增强逻辑5:事务回滚(模拟)System.out.println("【CGLIB代理-事务】回滚事务,异常:" + e.getMessage());throw e;} finally {System.out.println("【CGLIB代理-日志】" + method.getName() + " 方法执行结束\n");}return result;}
}
步骤 4:通过Enhancer生成代理对象并测试
import net.sf.cglib.proxy.Enhancer;public class CglibProxyTest {public static void main(String[] args) {// 1. 创建增强器(CGLIB核心类)Enhancer enhancer = new Enhancer();// 2. 配置增强器:设置目标类(父类)enhancer.setSuperclass(OrderService.class);// 3. 配置回调:关联方法拦截器enhancer.setCallback(new OrderServiceMethodInterceptor());// 4. 生成代理对象(目标类的子类实例)OrderService proxy = (OrderService) enhancer.create();// 5. 测试代理方法try {proxy.createOrder("ORDER_001"); // 非final方法,可被代理} catch (Exception e) {e.printStackTrace();}System.out.println("=== 测试final方法(无法被代理)===");proxy.cancelOrder("ORDER_001"); // final方法,增强逻辑不生效}
}
执行结果
【CGLIB代理-日志】createOrder 方法开始执行,参数:ORDER_001
【CGLIB代理-事务】开启事务
【核心业务】创建订单成功:ORDER_001
【CGLIB代理-事务】提交事务
【CGLIB代理-日志】createOrder 方法执行成功
【CGLIB代理-日志】createOrder 方法执行结束=== 测试final方法(无法被代理)===
【核心业务】取消订单成功:ORDER_001

4. CGLIB 代理的优缺点

优点
  • 可代理无接口类:无需目标类实现接口,弥补 JDK 代理的缺陷;
  • 性能较好:运行时通过MethodProxy.invokeSuper调用原始方法,无反射开销(比 JDK 代理运行时性能略优);
  • 支持类方法代理:可代理目标类的非 final 方法(无需接口)。
缺点
  • 依赖第三方库:需引入 CGLIB 依赖(底层依赖 ASM);
  • 不能代理 final 相关:final 类无法被继承,final 方法无法被重写,private/static 方法无法代理;
  • 代理类生成耗时:字节码操作比反射生成代理类耗时更长(首次生成代理类时开销较大)。

5. 适用场景

  • 目标类无接口(如遗留系统中的类);
  • 需代理类的非接口方法;
  • 框架底层增强(如 Spring AOP、Hibernate 延迟加载);
  • 追求运行时高性能(JDK8 + 后差距缩小,但仍有优势)。

五、三种代理技术全面对比

特性静态代理JDK 动态代理CGLIB 代理
代理类生成时机编译期(手动编写)运行时(反射动态生成)运行时(字节码动态生成)
实现方式实现同一接口 / 继承同一父类实现目标接口(代理类 = 接口实现类)继承目标类(代理类 = 目标类子类)
依赖无(纯 Java 基础)JDK 原生(java.lang.reflect)CGLIB 库(底层 ASM)
代理目标限制需实现接口 / 继承父类只能代理实现接口的类可代理类(非 final)、接口
方法限制无(手动控制)只能代理接口的 public 方法不能代理 final/private/static 方法
代码冗余度高(每个方法需重复增强逻辑)低(增强逻辑集中在 InvocationHandler)低(增强逻辑集中在 MethodInterceptor)
灵活性低(固定目标类 + 方法)中(基于接口,动态切换目标类)高(无接口依赖,支持多回调)
运行时性能高(无额外开销)中(反射调用开销)中 - 高(无反射,字节码生成耗时)
调试难度低(代码直观)中(反射调用,需调试 InvocationHandler)高(字节码生成,需理解 ASM)
典型应用简单固定场景(如工具类包装)Spring AOP(目标类有接口时)Spring AOP(目标类无接口时)、Hibernate

核心差异总结

  1. 生成时机:静态代理是 “编译期固定”,动态代理(JDK/CGLIB)是 “运行时动态”;
  2. 依赖关系:静态代理无依赖,JDK 代理依赖 JDK 原生,CGLIB 依赖第三方库;
  3. 代理目标:JDK 代理强依赖接口,CGLIB 代理强依赖继承,静态代理灵活但冗余;
  4. 性能:静态代理 > CGLIB 代理 ≈ JDK 动态代理(JDK8 + 后);
  5. 灵活性:CGLIB 代理 > JDK 动态代理 > 静态代理。

六、实际开发选型建议

  1. 优先选 JDK 动态代理:若目标类实现接口,优先使用 JDK 动态代理(无依赖、轻量、易维护);
  2. 无接口选 CGLIB:若目标类无接口,直接使用 CGLIB 代理(Spring AOP 默认自动切换);
  3. 简单场景选静态代理:若方法固定、增强逻辑简单,且无需扩展,可用静态代理(追求极致性能);
  4. 框架场景选动态代理:开发框架(如插件、AOP)时,优先使用 JDK/CGLIB 动态代理(灵活性高、可复用)。

Spring AOP 中的代理选择逻辑

       Spring AOP 默认采用 “自适应代理” 策略:

  • 若目标类实现接口,则使用 JDK 动态代理;
  • 若目标类无接口,则自动切换为 CGLIB 代理;
  • 若需强制使用 CGLIB 代理(即使目标类有接口),可通过配置proxy-target-class="true"开启。

七、常见问题与避坑指南

1. JDK 动态代理报错:ClassCastException

  • 原因:试图将代理对象强转为目标类(而非接口);
  • 解决:代理对象只能强转为目标类实现的接口(如IUserService proxy = (IUserService) Proxy.newProxyInstance(...))。

2. CGLIB 报错:Cannot subclass final class

  • 原因:目标类是 final 类,CGLIB 无法生成子类;
  • 解决:移除目标类的 final 修饰符,或改用 JDK 动态代理(若目标类可实现接口)。

3. 增强逻辑不生效

  • 静态代理:检查代理类是否重写了目标方法,且调用了目标对象的方法;
  • JDK 代理:检查目标类是否实现接口,InvocationHandler是否正确注入目标对象;
  • CGLIB 代理:检查目标方法是否为 final/private/static,Enhancer是否配置了setSuperclasssetCallback

4. 性能优化建议

  • 静态代理:无优化空间(本身性能最优);
  • JDK 代理:避免在invoke方法中做耗时操作,减少反射调用次数;
  • CGLIB 代理:优先使用MethodProxy.invokeSuper(而非Method.invoke),缓存Enhancer实例(避免频繁生成代理类)。

八、总结

       三种代理技术本质都是 “代理模式” 的实现,核心目标是解耦核心业务与增强逻辑,但适用场景各有侧重:

  • 静态代理:简单直接,适合固定场景,但冗余且不灵活;
  • JDK 动态代理:轻量无依赖,适合有接口的目标类,是日常开发的首选;
  • CGLIB 代理:灵活强大,适合无接口的目标类,是框架底层的常用选择。

       理解三种代理的原理和差异,不仅能帮助你在实际开发中精准选型,还能深入理解 Spring AOP、MyBatis 等框架的底层实现,提升技术深度。

http://www.dtcms.com/a/587031.html

相关文章:

  • 做免费外贸网站册域名滨州医学院做计算机作业的网站
  • 保山网站建设哪家好校园推广活动策划方案
  • 专业的会议网站建设民用网络架构
  • 多用户商城网站方案天津建设银行公积金缴费网站
  • 有趣网站之家无锡网站建设培训
  • 太原有网站工程公司吗it培训机构学费一般多少
  • 毕设做网站太简单网站 开发 工具
  • 截图按钮图标素材网站百度一wordpress
  • 长宁区网站建设网北京网站建设代理
  • 网站 的空间定制化开发是什么意思
  • 亿唐网不做网站做品牌原因网络市场调研
  • 专做机酒的网站北京附近做网站的公司
  • 【大型Qt工程国际化动态更新语言不成功】
  • 做的网站怎样适配手机屏幕定制网站制作报价
  • 使用cursor-free-vip时出现的错误及其解决方案
  • 【Hot100|9-LeetCode 438. 找到字符串中所有字母异位词】
  • 自已电脑做网站服务器广州平面设计
  • 个人备案网站做购物网站可以不网站建设合同应注意什么
  • 百度网站关键词手机主题如何自己制作网站
  • 网站前端开发得会什么软件小学生有没有必要学编程
  • 建站公司一般用什么框架wordpress主题添加菜单
  • 一文理清 CMake、Make、Kbuild、GCC 关系:从基础到进阶的构建工具链全解析
  • 桂林旅游网官方网站上海网站建设学校与管理中专
  • 中药饮片采购是什么?其市场动态与发展趋势如何?
  • 有做网站赚钱的吗wordpress 外网无法访问
  • 2025nessus工具最新(10.8.3)安装破解
  • 能够做物理题的网站ssh wordpress
  • 远程教育网站建设方案中建装饰集团有限公司官网
  • Go Beego 简介
  • 商城网站哪个公司做的好处泰安创意网络公司