2021-11-06
AOP概述
| Aspect Orieted Programming面向切面(方面)编程。 |
| 是一种编程模式,将分布在多个类中的功能封装到一个类中,这些功能称为cross-cutting concerns (横切关注点),如日志,事务,缓存,安全等等。 |
| 不是替代OOP,而是对其的补充。 |
软件纵向与横向结构

AOP的优点
| 减少了大量的代码重复。 |
| 功能组件之间的解耦。 |
常见AOP框架
AspectJ、Spring、Aspectwerkz、JBoss AOP...
AOP的类型
| 静态AOP |
| 修改应用程序的字节码,必要时会改变与扩展应用程序代码。 |
| 性能好,但是改动了切面需要重新编译整个应用程序。 |
| AspectJ提供了实现。 |
| 动态AOP |
| 实现过程是在运行时动态执行的。 |
| 性能稍差,但改动了切面无需重新编译整个应用程序。 |
| Spring使用代理机制实现。 |
AOP核心概念
| 概念 | 说明 |
| Advice,通知 | 需要单独封装的功能,定义在类的方法中。 |
| JoinPoint,连接点 | 可以使用通知的地方。 |
| PointCut,切入点 | 定义使用通知的连接点集合。 |
| Aspect,切面 | 通知和切入点的组合。 |
| Advisor,切面 | 通知和切入点的组合。 |
| Weaving,织入 | 把切面应用到应用程序中的过程。 |
| Target,目标 | 应用切面的对象。 |
| Introduction,引入 | 向现有的类添加新方法或新属性。 |
Spring AOP
实现机制
| 代理Bean使用ProxyFactory产生。 |
| 内部根据情况使用不同的代理实现。 |
| 代理Bean注入到调用者中供使用。 |

两种代理实现

连接点类型
| Spring只支持一种连接点类型:方法调用。 |
| 可以继承AspectJ提供更多类型的连接点支持。 |
通知类型

| 通知类型 | 说明 | |
| Before通知 | 方法调用之前执行。 | |
| 可以访问调用方法的目标,方法及参数,但不能控制方法本身的执行。 | ||
| 如果通知抛出异常,通知链后续的通知及方法本身都不会执行。 | ||
| Around通知 | 在方法调用之前和之后执行。 | |
| 可以改变方法的执行逻辑。 | ||
| After通知 | AfterReturning通知 | 方法调用且返回结果后执行。 |
| 可以访问调用方法的目标,方法,参数及返回值,但不能控制方法本身的执行。 | ||
| 如果目标方法抛出异常,通知不会执行。 | ||
| Throws通知 | 方法调用返回后执行,但是方法要抛出异常才会执行,一般用于处理特定的异常。 | |
| 必须实现特定的方法(不是接口声明的)afterThrowing(...) | ||
编程方式实现AOP
| 编写通知类,该类实现通知对应的接口。 |
| 使用ProxyFactory提供的方法设置目标及通知对象。 |
| 使用ProxyFactory获取目标的代理。 |
ProxyFactory类
| 构造方法 | |
| new ProxyFactory() | |
| new ProxyFactory(Object target) | |
| new ProxyFactory(Class<?>... proxyInterfaces) | |
| new ProxyFactory(Class<?> proxyInterfaces, Interceptor interceptor) | |
| new ProxyFactory(Class<?> proxyInterfaces, TargetSource targetSource) | |
| 普通方法 | |
| addAdvice()/removeAdvice() | 增加/移除Advice到/从通知链。 |
| setTarget()/setTargetClass() | 设置目标对象。 |
| addInterface()/setInterfaces() | 增加/设置目标类的接口。 |
| getProxy() | 创建并返回代理对象。 |
| adviceIncluded() | 判断Advice是否存在于通知链中。 |
| addAdvisor()/addAdvisors/removeAdvisor() | 增加/移除Advisor到/从通知链。 |
通知对应的接口

| Before | org.springframework.aop.MethodBeforeAdvice |
| AfterReturing | org.springframework.aop.AfterReturningAdvice |
| After | org.springframework.aop.AfterAdvice |
| Around | org.aopalliance.intercept.MethodInteceptor |
| Throws | org.springframework.aop.ThrowsAdvice |
| Introduction | org.springframework.aop.IntroductionInterceptor |
before通知
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(myBeforeAdvice);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice...");
}
}
class Target {
public void method() {
System.out.println("target method...执行...");
}
}
MyBeforeAdvice...
target method...执行...
afternReturning通知
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyAfterReturningAdvice myAfterReturningAdvice = new MyAfterReturningAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(myAfterReturningAdvice);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method();
}
}
class MyAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("MyAfterReturningAdvice...执行结果 " + o);
}
}
class Target {
public String method() {
System.out.println("target method1...执行...");
return "myAfterReturningAdvice执行结果...";
}
}
target method1...执行...
MyAfterReturningAdvice...执行结果 myAfterReturningAdvice执行结果...
Around通知
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyAroundAdvice myAroundAdvice = new MyAroundAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(myAroundAdvice);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method();
}
}
class MyAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("MyAroundAdvice start...");
Object result = methodInvocation.proceed();
System.out.println("方法执行结束..." + result);
System.out.println("MyAroundAdvice end...");
return null;
}
}
class Target {
public String method() {
System.out.println("target method...执行...");
return "MyAroundAdvice执行结果...";
}
}
MyAroundAdvice start...
target method...执行...
方法执行结束...MyAroundAdvice执行结果...
MyAroundAdvice end...
throws通知
| throwsAdvice方法调用返回后执行,但是方法要抛出异常才会执行,一般用于处理特定的异常。 |
| 必须实现特定的方法(不是接口声明的)。 |
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyThrowsAdvice myThrowsAdvice = new MyThrowsAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(myThrowsAdvice);
Target proxy = (Target)proxyFactory.getProxy();
try {
proxy.method();
} catch (Exception e) {
//e.printStackTrace();
}
}
}
class Target {
public void method() throws Exception{
System.out.println("target method...执行...");
throw new Exception("method error...");
}
}
注意:实现ThrowsAdvice接口的类必须是public修饰
public class MyThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
System.out.println("MyThrowsAdvice异常: " + ex.getMessage());
}
}
target method...执行...
MyThrowsAdvice异常: method error...
增加/设置目标类接口
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
//proxyFactory.setInterfaces(ITarget.class);
proxyFactory.addAdvice(myBeforeAdvice);
//ITarget proxy = (ITarget)proxyFactory.getProxy();
Target proxy = (Target) proxyFactory.getProxy();
System.out.println(proxy);
proxy.method();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target implements ITarget{
public void method(){
System.out.println("before");
}
}
interface ITarget{
void method();
}
MyBeforeAdvice...
org.crazy.aop.Target@6b71769e
MyBeforeAdvice...
before
Pointcut接口
使用advice通知时,在方法调用时都会使用相关定义的通知,某些非必要的方法就不需要通知如toString(),此时就需要切入点,指定具体哪些方法需要通知。
该接口表示切入点
| ClassFilter getClassFileter() | ClassFilter接口,用于匹配切入点或引入的目标类。 |
| MethodMatcher getMethodMatcher() | MethodMatcher接口:用于匹配方法是否是合适的切入点以便应用切面。 |
MethodMatcher接口的实现支持静态与动态两种类型,取决于首先调用法isRuntime()的返回值。
| 返回true | 动态,先调用一次matches(Method m, Class<?> targetClass)方法,若该方法返回true,则后续调用matches(Method m, Class<?> targetClass, Object[] args)方法。 |
| 返回false | 静态,只调用一次matches(Method m, Class<?> targetClass)方法。 |
检查切入点时,首先调用getClassFileter()方法检查目标类是否匹配,若返回true,再调用getMethodMatcher()检查方法是否匹配。
Spring提供了若干Pointcut的实现类
| StaticMethodMatcherPointcut | 实现静态MethodMatcher的抽象类。 重写其matches(Method method, @Nullable Class<?> targetClass)实现逻辑。 | |
| JdkRegexpMethodPointcut | 使用Jdk的正则表达式匹配。 | |
| NameMatchMethodPointcut | 使用方法名的简单匹配。 | |
| DynamicMethodMatchetPointcut | 实现动态MethodMatcher的抽象类。 重写其matches(Method method, Class<?> targetClass, Object... args)实现逻辑。 | |
| AnnotationMatchingPointcut | 用于匹配特定注解修饰的类或方法。 | |
| AspectJExpressionPointcut | 使用AspectJ表达式作为切入规则; 需要AspectJ支持。 | |
| ComposablePointcut | 用于操作多个Pointcut。 | |
| ControlFlowPointcut | 切面应用于从指定类中调用的方法。 | |
StaticMethodMatcherPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
Pointcut pointcut = new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> aClass) {
return "method2".equals(method.getName());
}
};
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
Target method1() running...
MyBeforeAdvice...
Target method2() running...
DynamicMethodMatchetPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
Pointcut pointcut = new DynamicMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> aClass, Object... objects) {
return "method1".equals(method.getName()) && objects.length > 0 && objects[0].equals("one");
}
};
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
Target method1() running...
MyBeforeAdvice...
Target method1(String) running...
Target method2() running...
JdkRegexpMethodPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern(".*method1.*");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
MyBeforeAdvice...
Target method1() running...
MyBeforeAdvice...
Target method1(String) running...
Target method2() running...
NameMatchMethodPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("method1");
pointcut.setMappedName("method2");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
Target method1() running...
Target method1(String) running...
MyBeforeAdvice...
Target method2() running...
AnnotationMatchingPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
//AnnotationMatchingPointcut pointcut = new AnnotationMatchingPointcut(MyAnnotation.class);
AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forMethodAnnotation(MyAnnotation.class);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
@MyAnnotation
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({ElementType.TYPE,ElementType.METHOD})
@interface MyAnnotation {
}
Target method1() running...
Target method1(String) running...
Target method2() running...
AspectJExpressionPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* method*(..))");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
MyBeforeAdvice...
Target method1() running...
MyBeforeAdvice...
Target method1(String) running...
MyBeforeAdvice...
Target method2() running...
ComposablePointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* method1*(..))");
AnnotationMatchingPointcut pointcut1 = AnnotationMatchingPointcut.forMethodAnnotation(MyAnnotation.class);
ComposablePointcut pointcut2 = new ComposablePointcut((Pointcut)pointcut);
pointcut2.intersection(pointcut1);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
@MyAnnotation
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
@MyAnnotation
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
@Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target({ElementType.TYPE,ElementType.METHOD})
@interface MyAnnotation {
}
MyBeforeAdvice...
Target method1() running...
MyBeforeAdvice...
Target method1(String) running...
Target method2() running...
ControlFlowPointcut
public class MyAdvice {
public static void main(String[] args) {
Target target = new Target();
MyBeforeAdvice myBeforeAdvice = new MyBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory();
ControlFlowPointcut pointcut = new ControlFlowPointcut(Service.class, "doService");
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut,myBeforeAdvice);
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
Target proxy = (Target)proxyFactory.getProxy();
proxy.method1();
proxy.method1("one");
proxy.method2();
new Service().doService(proxy);
}
}
class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("MyBeforeAdvice... ");
}
}
class Target {
public void method1(){
System.out.println("Target method1() running...");
}
public void method1(String str){
System.out.println("Target method1(String) running...");
}
public void method2(){
System.out.println("Target method2() running...");
}
}
class Service{
public void doService(Target target) {
target.method1();
}
}
Target method1() running...
Target method1(String) running...
Target method2() running...
MyBeforeAdvice...
Target method1() running...
Advisor接口
该接口表示切面,有两个子接口:
| PointcutAdvisor | DefaultPointcutAdvisor是PointcutAdvisor的默认实现。 |
| NameMatchMethodPointcutAdvisor | |
| RegexpMethodPointcutAdvisor | |
| AspectJPointcutAdvisor | |
| IntroductionAdvisor |
Pointcus类:
| 该类提供了两个常量及若干工具方法。 | |
| 常量 | SETTERS: 匹配set方法的Pointcut |
| GETTERS: 匹配get方法的Pointcut | |
| 方法 | Pointcut union(Pointcut pc1, Pointcut pc2) |
| Pointcut intersection(Pointcut pc1, Pointcut pc2) | |
Introduction引入:
| Introduction,可以在不改变目标对象的情况下动态引入新功能到已存在的对象上。 |
| 新功能使用实现了某个接口的类进行封装。 |
| 实际上是一个特殊类型的Around(环绕)通知。 |
| 只用于类级别上。 |
引入的实现方式:
| 声明接口 | 定义需要引入实现的方法; |
| 声明引入 | 实现自定义的接口及IntroductionInterceptor接口(通常继承该接口的实现类DelegatingIntroductionInterceptor); |
| 使用引入 | 直接将其作为Advice增加到ProxyFactory中。 |
| 实现IntroductionAdvisor接口,通常继承实现类DefaultIntroductionAdvosor,将引入作为参数传递给其构造方法,同时提供可选的IntroductionInfo限定类型,然后将其作为Advisor增加到ProxyFactory中。 |
实现方式一:
public class IntroductionTest {
public static void main(String[] args) {
Watch watch = new Watch();
MyCallWatch myCallWatch = new MyCallWatch();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(watch);
factory.addAdvice(myCallWatch);
factory.setOptimize(true);//
Watch w1 =(Watch)factory.getProxy();
w1.showTime();
CallWatch w2 = (CallWatch)w1;//将代理对象转换成合适的接口类型
w2.call();
}
}
class Watch {
public void showTime() {
System.out.println("My watch can showTime...");
}
}
interface CallWatch {
void call();
}
class MyCallWatch extends DelegatingIntroductionInterceptor implements CallWatch {
@Override
public void call() {
System.out.println("My watch can call phone...");
}
}
My watch can showTime...
My watch can call phone...
实现方式二:
public static void main(String[] args) {
Watch watch = new Watch();
MyCallWatch myCallWatch = new MyCallWatch();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(watch);
factory.addAdvisor(new MyNewFunctionAdvisor(myCallWatch));
factory.setOptimize(true);//
Watch w1 =(Watch)factory.getProxy();
w1.showTime();
CallWatch w2 = (CallWatch)w1;//将代理对象转换成合适的接口类型
w2.call();
RecordSport w3 = (RecordSport)w1;
w3.recordSport();
}
}
class Watch {
public void showTime() {
System.out.println("My watch can showTime...");
}
}
interface CallWatch {
void call();
}
interface RecordSport {
void recordSport();
}
class MyCallWatch extends DelegatingIntroductionInterceptor implements CallWatch, RecordSport {
@Override
public void call() {
System.out.println("My watch can call phone...");
}
@Override
public void recordSport() {
System.out.println("My watch can record sports...");
}
}
class MyNewFunctionAdvisor extends DefaultIntroductionAdvisor {
public MyNewFunctionAdvisor(Advice advice) {
super(advice, new IntroductionInfo() {
@Override
public Class<?>[] getInterfaces() {
return new Class[] {CallWatch.class, RecordSport.class};
}
});
}
}
My watch can showTime...
My watch can call phone...
My watch can record sports...
ProcxyFactory

浙公网安备 33010602011771号