一、代理模式

代理模式的分类:

  • 静态代理
  • 动态代理

从租房子开始讲起:中介与房东有同一的目标在于租房

1.静态代理

静态代理角色分析:

  • 抽象角色:一般使用接口或者抽象类来实现(这里为租房接口)

    public interface Rent {
    void rent();
    }
  • 真实角色:被打理的角色(这里为房东)

    public class HouseMaster implements Rent{
    public void rent() {
    System.out.println("房东租房啦!");
    } public static void main(String[] args) {
    HouseMaster houseMaster = new HouseMaster();
    Proxy proxy = new Proxy(houseMaster);
    proxy.rent();
    }
    }
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作

    public class Proxy {
    HouseMaster houseMaster; public Proxy() {
    } public Proxy(HouseMaster houseMaster) {
    this.houseMaster = houseMaster;
    } public void rent(){
    lookHouse();
    houseMaster.rent();
    sign();
    } public void lookHouse(){
    System.out.println("看房子");
    } public void sign(){
    System.out.println("签合同");
    }
    }
  • 客户:使用代理角色来进行一些操作

    public static void main(String[] args) {
    HouseMaster houseMaster = new HouseMaster();
    Proxy proxy = new Proxy(houseMaster);
    proxy.rent();
    }

    优点:

    (1).真实对象更加纯粹,不在关注一些琐碎的公共事务

    (2).公共业务由代理对象完成,有利于公共业务的扩展和管理

    缺点:多了代理对象也增加了代码量(所以后面出现了动态代理模式)

  1. 动态代理

    角色分析:与静态代理相同

    特点:动态代理的动态类是动态生成的,不是我们直接写好的

    分类:

    (1).基于接口的动态代理——JDK动态代理(重点理解)

    (2).基于类的动态代理——cglib

    (3).javasist

    核心api:

    (1).Proxy:

    Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

    • newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h):返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。

      参数:

      (1).loader类加载器

      (2).代理对象的接口

      (3).InvocationHandler的实体,因为一般是调用类继承了InvocationHandler,所以许多时候就是this

    (2).InvocatioinHandler:

    InvocationHandler是由代理实例的调用处理程序实现的接口

    每个代理实例都有一个关联的调用处理程序(也就是一个代理类)。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

    • invoke

      参数:

      (1).proxy:调用该方法的代理实例

      (2).method:所述方法对应于调用代理实例上的接口方法的实例

      (3).args:参数,如果没有则为null

    使用:

    1. 构建动态代理对象(这个代理对象可以用于同一个接口的多个实现类)

      public class ProxyInvocationHandler implements InvocationHandler {
      
          //代理对象
      Object target; //设定动态代理的对象
      public void setTarget(Object target){
      this.target = target;
      } public Object getProxy(){
      return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
      } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      Object res = method.invoke(target, args);
      return res;
      }
      }
    2. 测试

      public class service {
      
          public static void main(String[] args) throws Throwable {
      ProxyInvocationHandler handler = new ProxyInvocationHandler();
      handler.setTarget(new HostImpl());
      Host proxy = (Host) handler.getProxy();
      proxy.rent();
      }
      }
    3. 解释:从构建动态代理对象的过程查看

      (1).设定动态代理对象:setTarget()

      (2).获得动态代理getProxy()

      (3).使用动态代理,表面上看是调用了proxy.rent,本质上还是调用handler实现的invoke函数,注意该函数的第一个参数proxy用处不大

    优点:在静态代理的基础上,静态代理是代理的是一个类;而动态代理是代理一个接口(多个类)

二、AOP

AOP:面向切面编程,通过预编译方式和运行期动态代理实现 程序功能的统一维护的一种技术

导入织入包

两种方式:

  1. 使用api接口

    (1).MethodBeforeAdvice:方法的前置增强

    (2).AfterReturningAdvice:方法的后置增强

    环境搭建:

    //接口
    public interface service {
    void say();
    } //实例
    public class serviceImpl implements service {
    public void say() {
    System.out.println("say some thins");
    }
    } //前置增强
    public class beforeSay implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
    System.out.println("Good Morning!");
    }
    } //后置增强
    public class afterSay implements AfterReturningAdvice {
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
    System.out.println("后置增强");
    }
    }

    配置文件:

    <?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="serviceImpl" class="com.guan.dao.serviceImpl"/>
    <bean id="beforeSay" class="com.guan.dao.beforeSay"/>
    <bean id="afterSay" class="com.guan.dao.afterSay"/> <aop:config>
    <!-- choose pointCut-->
    <!-- public method.(args)-->
    <aop:pointcut id="point" expression="execution(* com.guan.dao.service.*(..))"/> <aop:advisor advice-ref="beforeSay" pointcut-ref="point"/>
    <aop:advisor advice-ref="afterSay" pointcut-ref="point"/>
    </aop:config> </beans>

    注:

    (1).<aop:point>设定切入点

    (2).<aop:advisor>设定环绕对象(主要设定前置函数,后置函数及其目标的切入点)

    (3).execution(* com.guan.dao.service.*(..))execution(* com.guan.dao.*.*(..)):所有修饰符(public,private) com.guan.dao包下的所有类下的所有方法的所有参数

    测试:

    public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    service bean = context.getBean("serviceImpl", service.class);
    bean.say();
    }

    注:这里返回的必须用接口类型(service),而不能用serviceImpl

  2. 使用切面

    环境搭建:

    package com.guan.dao;
    
    public class Advice {
    
        public void before(){
    System.out.println("before");
    } public void after(){
    System.out.println("after");
    } }

    配置文件:

    <?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="advice" class="com.guan.dao.Advice"></bean>
    <bean id="serviceImpl" class="com.guan.dao.serviceImpl"></bean> <aop:config>
    <aop:aspect ref="advice">
    <aop:pointcut id="point" expression="execution(* com.guan.dao.serviceImpl.*(..))"/>
    <!-- 切面-->
    <aop:before method="before" pointcut-ref="point"></aop:before>
    <aop:after method="after" pointcut-ref="point"></aop:after>
    </aop:aspect>
    </aop:config> </beans>

    测试类:

    public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    service bean = context.getBean("serviceImpl", service.class);
    bean.say();
    }
    //同上

    注:

    (1).注意<aop:aspect>的ref是相关的构成切面的类

    (2).在这个类的内部还是需要切入点的

  3. 使用api接口和使用切面比较

    (1).使用api接口需要记录相关的文档,但使用切面则可以在xml文件中直接配置

    (2).使用api接口需要多个类继承相关的接口,而使用切面只需要一个类承载相关的方法即可

    (3).使用api接口由于有对切入点的结果关联,所以和上下文的关联更密切;使用切面则切面的函数与切入点的上下文关系是割裂的

  4. 使用注解使用AOP

    相关注解:

    (1).@Aspect:标注这个类是一个切面

    (2).@Before("切入点")

    (3).@After("切入点后")

    (4).@Around:功能复杂,需要相关的方法使用ProceedingJoinPoint类型的参数,且这个参数可以直接调用方法

    (5).@EnableAspectJAutoProxy:用于注解开启注解(不用xml配置<aop:aspectj-autoproxy/>)

    注意:切入点都要用execution表达式

    环境搭建:

    @Aspect
    public class AnnotationCutPoint {
    @Before("execution(* com.guan.dao.*.*(..))")
    public void before(){
    System.out.println("before");
    } @After("execution(* com.guan.dao.*.*(..))")
    public void after(){
    System.out.println("after");
    } @Around("execution(* com.guan.dao.*.*(..))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("around1");
    joinPoint.proceed();
    System.out.println("around2");
    }
    }

    注意:先要有切面@Aspect,才有切点

    <?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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="serviceImpl" class="com.guan.dao.serviceImpl"></bean>
    <bean id="annotation" class="com.guan.dao.AnnotationCutPoint"></bean> <aop:aspectj-autoproxy/> </beans>

    测试:

    public class serviceImpl implements service {
    public void say() {
    System.out.println("say some thins");
    } public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    service bean = context.getBean("serviceImpl", service.class);
    bean.say();
    }
    }

    注:spring的AOP默认是通过jdk生成,但也可以进行修改

    <!--    jdk,默认-->
    <aop:aspectj-autoproxy proxy-target-class="false"/>
    <!-- cglib-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

spring——AOP(静态代理、动态代理、AOP)的更多相关文章

  1. 【spring基础】AOP概念与动态代理详解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...

  2. Spring AOP实现原理-动态代理

    目录 代理模式 静态代理 动态代理 代理模式 我们知道,Spring AOP的主要作用就是不通过修改源代码的方式.将非核心功能代码织入来实现对方法的增强.那么Spring AOP的底层如何实现对方法的 ...

  3. Spring Boot实践——Spring AOP实现之动态代理

    Spring AOP 介绍 AOP的介绍可以查看 Spring Boot实践——AOP实现 与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改 ...

  4. Spring AOP中的动态代理

    0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  Spring AOP中的动态代理机制 2.1  ...

  5. 转:Spring AOP中的动态代理

    原文链接:Spring AOP中的动态代理 0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  S ...

  6. spring---aop(4)---Spring AOP的CGLIB动态代理

    写在前面 前面介绍了Spring AOP的JDK动态代理的过程,这一篇文章就要介绍下Spring AOP的Cglib代理过程. CGLib全称为Code Generation Library,是一个强 ...

  7. 【Spring Framework】Spring入门教程(五)AOP思想和动态代理

    本文主要讲解内容如下: Spring的核心之一 - AOP思想 (1) 代理模式- 动态代理 ① JDK的动态代理 (Java官方) ② CGLIB 第三方代理 AOP概述 什么是AOP(面向切面编程 ...

  8. 转:AOP与JAVA动态代理

    原文链接:AOP与JAVA动态代理 1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代 ...

  9. AOP与JAVA动态代理

    1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代理类的字节码 2.AOP各种实现机制 ...

  10. 8、Spring教程之静态代理/动态代理

    为什么要学习代理模式,因为AOP的底层机制就是动态代理! 代理模式: 静态代理 动态代理 学习aop之前 , 我们要先了解一下代理模式! 静态代理 静态代理角色分析 抽象角色 : 一般使用接口或者抽象 ...

随机推荐

  1. shell脚本三剑客之sed

    shell脚本之sed命令 1.概述 2.工作流程 3.命令格式 4.具体操作 1.概述: 1.sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流 2.sed编辑器 ...

  2. 剑指Offer系列_09_用两个栈实现队列

    package leetcode.sword_to_offfer.day01; import java.util.LinkedList; /** * 用两个栈实现一个队列.队列的声明如下,请实现它的两 ...

  3. 01 前端基础之HTML

    目录 前端基础之HTML HTML简介 如何创建及展示 head内常见标签 body内基本标签 特殊符号 常见标签 标签的两大重要属性 列表标签 表格标签 form表单(很重要) 初次体验前后端交互 ...

  4. 05 BOM与DOM

    BOM和DOM 1. 什么是BOM和DOM 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的 ...

  5. Solution -「POI 2014」「洛谷 P5904」HOT-Hotels 加强版

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的树,求无序三元组 \((u,v,w)\) 的个数,满足其中任意两点树上距离相等.   \(n\le1 ...

  6. 分享一些访问之后显示本机公网ip的url地址

    http://ip.42.pl/raw https://api.ip.sb/ip http://ip.3322.net http://ip.qaros.com http://ip.cip.cc htt ...

  7. JVM学习——内存空间(学习过程)

    JVM--内存空间 关于内存的内容,内存的划分.JVM1.7 -> 1.8的变化比较大 JVM指令执行的时候,是基于栈的操作.每一个方法执行的时候,都会有一个属于自己的栈帧的数据结构.栈的深度, ...

  8. mysql视图,索引

    一.视图 View 视图是一个虚拟表,是sql语句的查询结果,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据,在使用视图时动态生成.视图的数据变化会影响到基表,基表的数据变化也会 ...

  9. 关于tomcat 访问80端口失效 阿里云问题版

    可能有朋友在配置完阿里云  配置好服务器发现 使用默认80端口访问网址失效 用8080依然失效  - -放心你用什么都会失效 并且你怎么杀接口也没用 答案就是 你的里面绝对没有80 和8080  你没 ...

  10. Django框架路由分发-名称空间

    目录 一:路由分发 1.路由分发简介 2.总路由分发配置 3.总路由终极配置(不需要导应用路由,直接点应用即可) 4.子路由配置 二:名称空间 1.名称空间应用场景 3.解决方式二>>&g ...