代理模式和面向切面编程

前言:从代理的角度总结Spring AOP

一、静态代理:你不知道我想做什么,我也不关心你做了什么

package simpleproxy;

// 设计一个接口
interface Shape {
    void draw();

    void erase();

}

// 接口的实现
class Rectangle implements Shape {

    @Override
    public void draw() {
        System.out.println("draw Rectangle");
    }

    @Override
    public void erase() {
        System.out.println("erase Rectangle");
    }

}

// 针对接口设计代理,添加代理的逻辑
class SimpleProxy implements Shape {
    Shape shape;

    void setShape(Shape shape) {
        this.shape = shape;
    }

    @Override
    public void draw() {
        System.out.println("create Rectangle");
        shape.draw();
    }

    @Override
    public void erase() {
        shape.erase();
        System.out.println("destroy Rectangle");
    }
}

public class SimpleProxyDemo {
    private Shape shape;

    public SimpleProxyDemo(Shape shape) {
        this.shape = shape;
    }

    public static void main(String[] args) {
        Rectangle target = new Rectangle();
        SimpleProxy proxy = new SimpleProxy();
        proxy.setShape(target);
        SimpleProxyDemo demo = new SimpleProxyDemo(proxy);
        demo.shape.draw();
        demo.shape.erase();
    }
}

或许大多数时候通过这样的方式实现代理已经足够了,不过这只是故事的开始。

二、JDK动态代理:反射遇上动态编译

JDK动态代理的本质是通过反射形成.java文件,再利用动态编译生成.class文件

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Shape {
    void draw();

    void erase();

}

class Rectangle implements Shape {

    @Override
    public void draw() {
        System.out.println("draw Rectangle");
    }

    @Override
    public void erase() {
        System.out.println("erase Rectangle");
    }

}

// 把代理的逻辑放在InvocationHandler实现类中,从而可以让任意接口代理相同的逻辑
class Handler implements InvocationHandler {
    Object targer;

    Handler(Object targer) {
        this.targer = targer;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("create Target");
        Object o = method.invoke(targer, args);
        System.out.println("destroy Target");
        return o;
    }

}

public class DynamicProxyDemo {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle();
        Handler h = new Handler(rectangle);
        Shape proxy = (Shape) Proxy.newProxyInstance(Rectangle.class.getClassLoader(), Rectangle.class.getInterfaces(),
                h);
        proxy.draw();
        proxy.erase();
    }
}

三、CGLIB动态代理:字节码技术的辉煌一笔

需要引入的两个依赖关系

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>4.2</version>
</dependency>

当代理对象不是通过接口实现的时候,JDK动态代理就失去了往日的荣光。可是孜孜不倦的程序员们永远不会停住前进的脚步,胜利的旗帜又一次插在了巫妖王的城堡上。

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 丢失的Shape接口
class Rectangle {
    public void draw() {
        System.out.println("Draw Rectangle");
    }

    public void erase() {
        System.out.println("Erase Rectangle");
    }
}

// 共同的代理逻辑
class Interceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("create Target");
        Object o = proxy.invokeSuper(obj, args);
        System.out.println("destroy Target");
        return o;
    }
}

public class CglibDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Rectangle.class);
        enhancer.setCallback(new Interceptor());
        Rectangle proxy = (Rectangle) enhancer.create();
        proxy.draw();
        proxy.erase();
    }
}

四、Spring AOP:面向切面的集大成者

无论是JDK的实现方式还是CGLIB的字节码技术,我们都可以利用Spring AOP做最后的统一处理。要说利用Spring AOP创建代理的唯一不足之处就是,无论被代理对象还是代理对象本身都必须交给Spring容器来管理,如果你仅仅是希望实现一个简单的代理逻辑而并不愿意大范围修改代码,引入Spring显然过于笨重。

一个简单的Service接口

package aop;

public interface Service {
    void bar();
}

创建ServiceImpl类实现上述接口

package aop;

public class ServiceImpl implements Service {

    @Override
    public void bar() {
        System.out.println("service bar");
    }
}

编写ServiceB类(没有实现接口的被代理对象)

package aop;

public class ServiceB {
    public void throwException(int type) {
        System.out.println("service B");
        if (type == 1) {
            throw new IllegalArgumentException("测试异常");
        }
    }
}

编写功能齐备的代理逻辑

package aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class AdviceImpl {
    // 方法前插入
    public void doBefore(JoinPoint jp) {
        System.out.println(
                "log Begining method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());
    }

    // 方法后插入
    public void doAfter(JoinPoint jp) {
        System.out.println(
                "log Ending method: " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName());
    }

    // 前后一起插入的完整逻辑
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long time = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        time = System.currentTimeMillis() - time;
        System.out.println("process time: " + time + " ms");
        return retVal;
    }

    // 捕获异常,相当于把被代理对象放置在try...catch中
    public void doThrowing(JoinPoint jp, Throwable ex) {
        System.out.println("method " + jp.getTarget().getClass().getName() + "." + jp.getSignature().getName()
                + " throw exception");
        System.out.println(ex.getMessage());
    }
} 

通过xml文件配置切面、切点和建言。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <aop:config>
        <aop:aspect id="aspect" ref="aspectBean">
            <aop:pointcut id="businessService" expression="execution(* aop.*.*(..))" />
            <aop:before pointcut-ref="businessService" method="doBefore" />
            <aop:after pointcut-ref="businessService" method="doAfter" />
            <aop:around pointcut-ref="businessService" method="doAround" />
            <aop:after-throwing pointcut-ref="businessService"
                method="doThrowing" throwing="ex" />
        </aop:aspect>
    </aop:config>
    <bean id="aspectBean" class="aop.AdviceImpl" />
    <bean id="service" class="aop.ServiceImpl" />
    <bean id="serviceB" class="aop.ServiceB" />
</beans>

通过junit演示

package aop;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopTest {
    @Test
    public void aop() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop/spring.xml");
      // 查看所有对象是否都正确的交给spring来管理
        for (String beanName : ctx.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
        System.out.println("===============伟大的分割线================");
        ServiceB serviceB = (ServiceB) ctx.getBean("serviceB");
        serviceB.throwException(1);
    }
}

之前我曾经写过一篇博客专门总结过spring官方文档有关aop的章节,感兴趣的朋友可以自己查看。

时间: 2024-10-03 21:53:38

代理模式和面向切面编程的相关文章

说说Python的装饰器模式与面向切面编程

说说Python的装饰器模式与面向切面编程 今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用.概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能. 1. 装饰器入门 1.1. 需求是怎么来的? 装饰器的定义很是抽象,我们来看一个小例子. //edit http://www.lai18.com //date 2

Web项目中静态代理和动态代理为基础的面向切面编程AOP

本来每天更新的,我一般喜欢夜里过了十二点的时候发文章,结果难道是愚人节吗?学校的网也很有意思,断了,把我给耍了...好吧-开始今天的话题AOP.AOP太重要了,所以放到第二篇文章来谈这个话题,AOP是Spring中的重要概念.如果这个不理解Web开发中的三大框架的原理,那就呵呵了.时常听到同学和网友议论Web程序员大部分时间都是在考皮XML配置,我当时听到也是醉了,所以我要用心学习Web,其实这里面蕴含的设计模式.算法.架构思想在源码中体现的淋漓尽致啊,一个大宝库竟然视而不见可惜了.下面就一起品

面向切面编程AOP之动态代理

动态代理的作用是:最终是为了学习AOP(面向切面编程):    拓展一下:OOP是什么?  OOP是面向对象编程!! 面向切面--->与装饰者模式有点相似 --->比装饰者模式还要灵活 学习动态代理,我们只需要学习一下一个类即可 Proxy类,并对该类下的一个静态方法newProxyInstance()进行学习 直接上代码:

Java实战之03Spring-03Spring的核心之AOP(Aspect Oriented Programming 面向切面编程)

三.Spring的核心之AOP(Aspect Oriented Programming 面向切面编程) 1.AOP概念及原理 1.1.什么是AOP OOP:Object Oriented Programming面向对象编程 AOP:Aspect Oriented Programming面向切面编程 1.2.代理 充分理解:间接 主要作用:拦截被代理对象执行的方法,同时对方法进行增强. 1.2.1.静态代理 特点:代理类是一个真实存在的类.装饰者模式就是静态代理的一种体现形式. 1.2.2.动态代

面向切面编程(AOP)

        AOP.OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想: OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分.对于"雇员"这样一个业务实体进行封装,自然是OOP/OOD的任务,我们可以为其建立一个"Employee"类,并将"雇员"相关的属性和行为封装其中. 而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中

依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦(转good)

依赖注入(DI)有助于应用对象之间的解耦,而面向切面编程(AOP)有助于横切关注点与所影响的对象之间的解耦.所谓横切关注点,即影响应用多处的功能,这些功能各个应用模块都需要,但又不是其主要关注点,常见的横切关注点有日志.事务和安全等. 将横切关注点抽离形成独立的类,即形成了切面.切面主要由切点和通知构成,通知定义了切面是什么,以及何时执行何种操作:切点定义了在何处执行通知定义的操作. http://ju.outofmemory.cn/entry/216839 引子: AOP(面向方面编程:Asp

Spring之面向切面编程AOP(二)

简介 当积累的知识点到一定量的时候,学新知识就变得容易多了.希望再接下来的学习顺利进行下去.今天知识也是挺简单的,主要就是AOP面向切面编程.其中牵涉到了JDKProxy和CGLIB两个代理类,如何使用好,加以深刻理解.学起Spring切面编程也就简单多了 代理模式 1. 代理模式介绍 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对

使用Spring进行面向切面编程(AOP)

转载于http://www.blogjava.net/supercrsky/articles/174368.html 文章太长,写的很好,没看完,转过来慢慢理解,品味 简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足. 除了类(classes)以外,AOP提供了 切面.切面对关注点进行模块化,例如横切多个类型和对象的事务管理. (这些关注点术语通常称作 横切(crosscutting) 关注点.) Spring的一个关键的组件就是 AOP

AOP面向切面编程

点击打开链接 理解AOP Posted on 2012-06-01 10:54 yanbin_new 阅读(30406) 评论(6) 编辑 收藏 Aspect Oriented Programming  面向切面编程.解耦是程序员编码开发过程中一直追求的.AOP也是为了解耦所诞生. 具体思想是:定义一个切面,在切面的纵向定义处理方法,处理完成之后,回到横向业务流. AOP 在Spring框架中被作为核心组成部分之一,的确Spring将AOP发挥到很强大的功能.最常见的就是事务控制.工作之余,对于