无论是代理模式还是AOP核心思想都是在不修改原来业务代码前提下,进行原来代码的增强

一:代理模式

代理作用:代理对象具有真实对象功能(比如真实对象有method1()那么代理对象也具有method1()),并且执行时让代理对象替代真是对象完成相应操作,并能够在执行前后对真实对象操作进行增强处理

代理模式使用场合:客户端不直接访问实际对象,而通过代理对象作为桥梁来完成间接访问

使用代理模式并不会创建新的方法,都是在真实类方法基础上进行增强,当然在增强方法中可以创建其他方法

 

 

 

1.静态代理VS动态代理

1.1静态代理:

静态代理:代理类和真实类实现同一个接口,这是静态代理的前提;代理类实现真实类同时对真实类方法进行增强处理

每一个不希望被修改的对象(SaveBusinessProcess)都要创建一个对应的代理类(SaveBusinessProcessProxy),这也正是静态代理的缺点。

  比如,除了SaveBusinessProcess还有UpdateBusinessProcess,DeleteBusinessProcess等,使用静态代理都需要创建对应的代理UpdateBusinessProcessProxy,DeleteBusinessProcessProxy

 

 

 

 初始SaveBusinessProcess在线上运行将数据存储到mysql——》在不更改SaveBusinessProcess存储数据到mysql前提下需要将这些数据保存到oracle——》新建代理类SaeBusinessProcessProxy,将SaveBusinessProcess作为成员变量

实例代码:

TestMain:
public class BusinessProcessTest {
    public static void main(String[] args){
        IBusinessProcess businessProcess=new SaveBusinessProcess();
        IBusinessProcess businessProcessProxy=new SaveBusinessProcessProxy(businessProcess);
        businessProcessProxy.dataProcess();
    }
}

Interface:
public interface IBusinessProcess {
    public void dataProcess();
}

Service:
public class SaveBusinessProcess implements IBusinessProcess {
    @Override
    public void dataProcess() {
        //dataprocess();  --业务处理逻辑
        System.out.println("save data process completed");
    }
}

Proxy:
public class SaveBusinessProcessProxy implements IBusinessProcess {
    private IBusinessProcess businessProcess;
    public SaveBusinessProcessProxy(IBusinessProcess businessProcess){
        this.businessProcess=businessProcess;
    }
    @Override
    public void dataProcess() {
        //addProcess() --需要加强的代码
        System.out.println("static proxy process");
        this.businessProcess.dataProcess();
    }
}
控制台输出:

  

1.2 动态代理(JDK动态代理 && CGLIB动态代理)

当真实类中方法增多,静态代理类也要添加相应的方法,所以需要引入动态代理

动态代理中代理类采用反射方式,在不用随着真实类方法增加而增加的前提下,为真实类提供方法增强的目的

1.2.1 JDK动态代理(接口代理)--反射获取真实类任意method

JDK动态代理核心点: 接口、反射、Proxy.newProxyInstance()、implements InovationHandler、invoke()

Jdk代理设计到java.lang.reflect包中InovacationHandler接口和Proxy类,核心方法是如下invoke()方法

invoke()作用:调用包装在当前Method对象中的方法

invoke()原型:Object invoke(Object obj, Method method, Object...args) obj:实例化后对象,method: 目标方法,args:用于方法调用的参数

invoke()返回:根据obj和args调用的方法的返回值

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {...}

public interface Person {

void wakeup();
    void sleep();
}



public class Mum implements Person{
    @Override
    public void wakeup() {
        System.out.println("mum wakeup");
    }

    @Override
    public void sleep() {
        System.out.println("mum sleep");
    }
}


public class Son implements Person{
    @Override
    public void wakeup() {
        System.out.println("son wakeup");
    }

    @Override
    public void sleep() {
        System.out.println("son sleep");
    }
}

public class JdkProxy implements InvocationHandler {
    private static final String method1="wakeup";
    private static final String method2="sleep";
    private Object bean;
    public JdkProxy(Object bean){
        this.bean=bean;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name= method.getName();
        if(StringUtils.equalsIgnoreCase(name,method1)){
            if(bean.getClass().getName().contains("Mum")){
                System.out.println("Mum is preparing breakfast");
            }else{
                System.out.println("Son is washing face");
            }
        }else if(StringUtils.equalsIgnoreCase(name,method2)){
            if(bean.getClass().getName().contains("Mum")){
                System.out.println("Mum is cleaning");
            }else{
                System.out.println("Son is dreaming");
            }
        }
        return method.invoke(bean,args);
    }
}

public class MainTest {
    public static void main(String[] args) {
        Person person=new Son();
        JdkProxy jdkProxy=new JdkProxy(person);  //创建代理类类型的引用proxy,传入son实例那么这个proxy对象就是代理的son实例
Person son
=(Person) Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Person.class},jdkProxy); //生成Son的代理实例.另外注意这里Person.class要是接口类 son.wakeup(); son.sleep(); System.out.println("--------------"); Person person1=new Mum(); JdkProxy jdkProxy1=new JdkProxy(person1); Person mum=(Person) Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Person.class},jdkProxy1); mum.wakeup(); mum.sleep(); } }

output:

Son is washing face
son wakeup
Son is dreaming
son sleep
--------------
Mum is preparing breakfast
mum wakeup
Mum is cleaning
mum sleep

JDK动态代理必须有接口原因:

这和JDK动态代理本身设计相关。点进Proxy.newProxyInstance()实现如下,可见JDK动态代理中生成的代理类需要传入被代理接口,并通过反射得到接口的方法对象,并将此方法对象传参给代理类的invoke()去执行,从而实现代理功能。所以接口是jdk动态代理的核心实现方式,没有接口就无法通过反射找到方法。

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

        final Class<?>[] intfs = interfaces.clone();
...
}

如果将上例中

Person person=new Son();
JdkProxy jdkProxy=new JdkProxy(person);
Person son=(Person) Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Person.class},jdkProxy);
改成

Son son=new Son();
JdkProxy jdkProxy=new JdkProxy(son);
Son son=(Son) Proxy.newProxyInstance(jdkProxy.getClass().getClassLoader(), new Class[]{Son.class},jdkProxy);

会报如下异常

Exception in thread "main" java.lang.IllegalArgumentException: proxymode.dynamicproxy.jdkproxy.Son is not an interface
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:590)
at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:557)
at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230)
at java.lang.reflect.WeakCache.get(WeakCache.java:127)
at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:419)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:719)
at proxymode.dynamicproxy.jdkproxy.MainTest.main(MainTest.java:9)

 

1.2.2 cglib动态代理

cglib动态代理不需要有接口存在,cglib动态代理过程中生成的是实现类的子类(Enhancer来生成实现类的子类)

 

public interface Person {
    void wakeup();
    void sleep();
}



public class Mum implements Person{
    @Override
    public void wakeup() {
        System.out.println("mum wakeup");
    }

    @Override
    public void sleep() {
        System.out.println("mum sleep");
    }
}


public class Son implements Person{
    @Override
    public void wakeup() {
        System.out.println("son wakeup");
    }

    @Override
    public void sleep() {
        System.out.println("son sleep");
    }
}


public class CglibProxy implements MethodInterceptor {
    private static final String method1="wakeup";
    private static final String method2="sleep";
    private Enhancer enhancer=new Enhancer();
    private Object bean;
    public CglibProxy(Object bean){
        this.bean=bean;
    }
    public Object getProxy(){        //cglib“凭空”创造一个原bean的子类,并把callback指向this,也就也是当前对象即这个proxy对象。从而调用intercept(),并且在intercept()中进行了附加功能的执行,并且最终还是调用原始bean的相应方法:son.wakeup() son.sleep()
        //设置要创建子类的类
        enhancer.setSuperclass(bean.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        String name= method.getName();
        if(StringUtils.equalsIgnoreCase(name,method1)){
            if(bean.getClass().getName().contains("Mum")){
                System.out.println("Mum is preparing breakfast");
            }else{
                System.out.println("Son is washing face");
            }
        }else if(StringUtils.equalsIgnoreCase(name,method2)){
            if(bean.getClass().getName().contains("Mum")){
                System.out.println("Mum is cleaning");
            }else{
                System.out.println("Son is dreaming");
            }
        }
        return method.invoke(bean,objects);
    }
}

public class MainTest {
    public static void main(String[] args) {
        Son son=new Son();
        CglibProxy cglibProxy=new CglibProxy(son); //创建代理类类型的引用proxy,传入son实例那么这个proxy对象就是代理的son实例
        Son son1=(Son) cglibProxy.getProxy();  //使用代理类调用getProxy()方法,并强制类型转换
        son1.wakeup();
        son1.sleep();
        System.out.println("--------------");
        Mum mum=new Mum();
        CglibProxy cglibProxy1=new CglibProxy(mum);
        Mum mum1=(Mum) cglibProxy1.getProxy();
        mum1.wakeup();
        mum1.sleep();
    }
}

 

output:

Son is washing face

son wakeup

Son is dreaming

son sleep

--------------

Mum is preparing breakfast

mum wakeup

Mum is cleaning

 

mum sleep

二: AOP

AOP:它不需要专门的编译方式和特殊的类装载器,它在运行期通过动态代理方式来实现将目标类织入性能监视代码

1. aop核心概念

切面(Aspect):一个模块化的横切逻辑(也称横切关注点),可能会横切多个对象。

连接点(Join point):程序执行中的某个具体执行点。如上例中原对象(非代理对象)的方法。

增强处理:切面在某个特定连接点上执行的代码逻辑。

切入点(pointcut):对连接点的特征进行描述,可使用正则表达式,类似于Servlet的url-pattern,用于匹配连接点(方法)。增强处理与一个切入点表达式相关联,并在与这个切入点匹配的某个连接点运行。

目标对象:被一个或多个切面增强的对象。

AOP代理(Proxy):由AOP所创建的对象,实现执行增强处理方法等功能,可以使JDK动态代理也可以是CGLIB代理;如果是接口,则可以使用JDK动态代理,如果是类(比如service只有一个实现,不需要使用接口或者Controller层只有一个实现)则使用CGLIB代理

织入:将增强处理连接到应用程序中的类型或对象上的过程,叫织入。

增强处理类型:在原对象的方法连接点之前插入的增强处理叫前置增强,在其之后的叫后置增强。此外还要环绕增强、异常抛出增强、最终增强等类型。
通知(advice),5种通知方式

  • @Before:前置通知,在调用目标方法之前执行通知定义的任务
  • @After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务
  • @After-returning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务
  • @After-throwing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务
  • @Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务。

2.AOP常用注解

@Aspect:作用:把当前类声明为切面类。

@Before:
作用:把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@AfterReturning
作用:把当前方法看成是后置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@AfterThrowing
作用:把当前方法看成是异常通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@After
作用:把当前方法看成是始终通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Around
作用:把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Pointcut
作用:指定切入点表达式
属性:
value:指定表达式的内容

@Order

作用: 指定切面执行顺序

@Aspect
// 切面执行顺序
@Order(3)
 

实例:(将监控代码AspectDemo 织入业务代码AspectTestService中,实现业务代码和监控代码的解耦)

 
ProjectApplication:
@SpringBootApplication
public class ProjectApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProjectApplication.class, args);
    }

}

Controller:
@RestController
@Slf4j
public class AspectTestController {
    @Autowired
    private AspectTestService aspectTestService;

    @RequestMapping("aoptest")
    public void test(){
        log.info("this is an aop controller...");
        aspectTestService.test("abc");
//        aspectTestService.testAgain();
    }
}

Srvice:
@Service
@Slf4j
public class AspectTestService {
    public void test(String name){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("this is an AOP test service ...");
    }
}

AOP:
@Aspect  定义切片类
@Component
@Slf4j
public class AspectDemo {
    @Before("pointCuteDemo()") 
    public void doBefore(){
        log.info("Aspect Demo before");
    }
    @Around("pointCuteDemo()")
    public Object logPerformance(ProceedingJoinPoint pjp) throws Throwable {
        long starttime = System.currentTimeMillis();
        String name = "-";
        String result = "Y";
        try {
            Object[] args=pjp.getArgs();              //获取方法参数值数组
            MethodSignature  methodSignature= (MethodSignature) pjp.getSignature(); //获取方法名
            Class[] paramTypeArray=methodSignature.getParameterTypes(); //获取方法参数类型
            name=methodSignature.toLongString();
            log.info("args:{},methodSignature:{},paramTypeArray:{}",args,methodSignature,paramTypeArray);
            return pjp.proceed();  //pjp.proceed()上边内容在调用com.fql.example.project.aop.service包下任意方法之前执行;pjp.proceed()下边内容在调用com.fql.example.project.aop.service包下任意方法之后执行
        } catch (Exception e) {
            result = "N";
            throw e;
        } finally {
            long endtime = System.currentTimeMillis();
            log.info("{},{},{}ms", name, result, endtime - starttime);
        }

    }

    @After("pointCuteDemo()")
    public void doAfter(){
        log.info("Aspect Demo After");
    }

    @Pointcut("execution(* com.fql.example.project.aop.service..*(..))")  //service包下的任意类的任意方法时均会调用此方法
    private void pointCuteDemo(){}

}

 

 

 

参考:https://www.cnblogs.com/wangenxian/p/10885309.html

https://www.cnblogs.com/leifei/p/8263448.html

https://blog.csdn.net/weixin_43953283/article/details/125783249

创建代理类类型的引用proxy,传入son实例那么这个proxy对象就是代理的son实例
posted on 2022-01-17 18:43  colorfulworld  阅读(170)  评论(0编辑  收藏  举报