spring基础概念AOP与动态代理理解

一、代理模式

代理模式的英文叫做Proxy或Surrogate,中文都可译为”代理“,所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

以简单模拟事务的执行过程说明各种代理区别

1.1 静态代理

由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

public interface PersonDao {

 void savePerson();
}
public class PersonDaoImpl implements PersonDao {

 @Override
 public void savePerson() {
  System.out.println("save person");
 }
}
public class Transaction {

 void beginTransaction(){
  System.out.println("begin Transaction");
 }

 void commit(){
  System.out.println("commit");
 }
}

接下来编写静态代理类---实现PersonDao接口

/**
 * 静态代理类
 * @author qjc
 */
public class PersonDaoProxy implements PersonDao{

 PersonDao personDao;
 Transaction transaction;

 public PersonDaoProxy(PersonDao personDao, Transaction transaction) {
  this.personDao = personDao;
  this.transaction = transaction;
 }

 @Override
 public void savePerson() {
  this.transaction.beginTransaction();
  this.personDao.savePerson();
  this.transaction.commit();
 }
}

测试

/**
 * 测试静态代理
 * @author qjc
 */
public class TestPersonProxy {

 @Test
 public void testSave(){
  PersonDao personDao = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  PersonDaoProxy proxy = new PersonDaoProxy(personDao, transaction);

  proxy.savePerson();
 }
}

总结:

1、静态代理模式并没有做到事务的重用

2、假设dao有100个类,100个proxy,接口中有多少方法,在proxy层就得实现多少方法,有多少方法就要开启和提交多少事务

3、如果一个proxy实现了多个接口,如果其中的一个接口发生变化(添加了一个方法),那么proxy也要做相应改变

1.2 JDK动态代理

动态代理类:在程序运行时,运用反射机制动态创建而成。

JDK的动态代理必须具备四个条件:1、目标接口 2、目标类 3、拦截器 4、代理类

使用上个例子的PersonDao接口、PersonDaoImpl类及Transaction类

编写拦截器

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

/**
 * 拦截器
 *   1、目标类导入进来
 *   2、事物导入进来
 *   3、invoke完成:开启事务、调用目标对象的方法、事务提交
 *
 * @author qjc
 */
public class Interceptor implements InvocationHandler {

 private Object target; // 目标类
 private Transaction transaction;

 public Interceptor(Object target, Transaction transaction) {
  this.target = target;
  this.transaction = transaction;
 }

 /**
  * @param proxy 目标对象的代理类实例
  * @param method 对应于在代理实例上调用接口方法的Method实例
  * @param args 传入到代理实例上方法参数值的对象数组
  * @return 方法的返回值,没有返回值是null
  * @throws Throwable
  */
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  String methodName = method.getName();
  if ("savePerson".equals(methodName)
    || "deletePerson".equals(methodName)
    || "updatePerson".equals(methodName)) {

   this.transaction.beginTransaction(); // 开启事务
   method.invoke(target); // 调用目标方法
   this.transaction.commit(); // 提交事务

  } else {
   method.invoke(target);
  }
  return null;
 }
}

测试

/**
 * 测试jdk动态代理
 * @author qjc
 */
public class TestJDKProxy {

 @Test
 public void testSave(){
  /**
   * 1、创建一个目标对象
   * 2、创建一个事务
   * 3、创建一个拦截器
   * 4、动态产生一个代理对象
   */
  Object target = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  Interceptor interceptor = new Interceptor(target, transaction);
  /**
   * 参数一:设置代码使用的类加载器,一般采用跟目标类相同的类加载器
   * 参数二:设置代理类实现的接口,跟目标类使用相同的接口
   * 参数三:设置回调对象,当代理对象的方法被调用时,会调用该参数指定对象的invoke方法
   */
  PersonDao personDao = (PersonDao) Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    interceptor);
  personDao.savePerson();
 }
}

总结

1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。

2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。

3、利用JDKProxy方式必须有接口的存在。

4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。

缺点:

1、在拦截器中除了能调用目标对象的目标方法以外,功能是比较单一的,在这个例子中只能处理事务

2、拦截器中的invoke方法的if判断语句在真实的开发环境下是不靠谱的,因为一旦方法很多if语句需要写很多。

1.3 CGLIB动态代理

使用上个例子的PersonDaoImpl类和Transaction类(不用接口)

编写拦截器类

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

/**
 * CGLIB代理 拦截器
 * @author qjc
 */
public class Interceptor implements MethodInterceptor {

 private Object target; // 代理的目标类
 private Transaction transaction;

 public Interceptor(Object target, Transaction transaction) {
  this.target = target;
  this.transaction = transaction;
 }

 /**
  * 创建目标对象的代理对象
  *
  * @return
  */
 public Object createProxy() {
  // 代码增强
  Enhancer enhancer = new Enhancer(); // 该类用于生成代理对象
  enhancer.setCallback(this); // 参数为拦截器
  enhancer.setSuperclass(target.getClass());// 设置父类
  return enhancer.create(); // 创建代理对象
 }

 /**
  * @param obj 目标对象代理类的实例
  * @param method 代理实例上 调用父类方法的Method实例
  * @param args 传入到代理实例上方法参数值的对象数组
  * @param methodProxy 使用它调用父类的方法
  * @return
  * @throws Throwable
  */
 public Object intercept(Object obj, Method method, Object[] args,
   MethodProxy methodProxy) throws Throwable {
  this.transaction.beginTransaction();
  method.invoke(target);
  this.transaction.commit();
  return null;
 }
}

测试

/**
 * 测试cglib动态代理
 * 通过cglib产生的代理对象,代理类是目标类的子类
 * @author qjc
 */
public class TestCglibProxy {

 @Test
 public void testSave(){

  Object target = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  Interceptor interceptor = new Interceptor(target, transaction);

  PersonDaoImpl personDaoImpl = (PersonDaoImpl) interceptor.createProxy();
  personDaoImpl.savePerson();
 }
}

总结:

1、CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

2、用CGlib生成代理类是目标类的子类。

3、用CGlib生成 代理类不需要接口

4、用CGLib生成的代理类重写了父类的各个方法。

5、拦截器中的intercept方法内容正好就是代理类中的方法体 CGLIB和JDK动态代理区别:

JDK:

目标类和代理类实现了共同的接口

拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方法体的内容

CGLIB:

目标类 是代理类的父类

拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体,使用字节码增强机制创建代理对象的.

二、面向切面编程

OOP(面向对象编程):封装、继承、多态、抽象

封装,对代码进行基本的管理、模块化的管理。每个类可能都有自己的职能,出了问题就是论事找人就行了。从修改角度讲,直接修改代码可能有风险,这不是个长远之计,最自然的是从类型封装变化。但是新的类型和旧的体系之间怎么去融合,所以说需要在类与类之间建立一种血缘关系。那么这就是继承的需求,通过继承就可以发现这些类之间是有关联的,它们之间是有父子关系的。然后在继承基础之上多态起决定性的特征。所以说一般认为面向对象最核心的特征,其实是多态。前面几个都是在做铺垫的。多态才是它最核心的特征。子类中通过重写方法,代表了扩展这个层面的东西,而它能融入老的体系中能够正常工作,这是重用这个层面的东西,新的方法、旧的体系、扩展和重用。

AOP(面向切面编程):

面向切面编程,是一种通过预编译方式运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术.

OOP与AOP区别:

  OOP:针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清楚的逻辑单元划分。

  AOP:针对业务处理过程中的横切逻辑 进行提取,它所面对的是处理过程中的某个步骤或者阶段,以获得逻辑过程中各部分之间低耦合的隔离效果。这两种设计思想在目标上有着本质的差异。AOP做到了代码块的重用。

spring AOP代理机制:

  1、若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。

     优点:因为有接口,所以使系统更加松耦合

      缺点:为每一个目标类创建接口

  2、若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

      优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。

      缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。

使用第一个例子的 PersonDao接口、PersonDaoImpl类和Transaction类

编写spring配置

 <bean id="personDao" class="cn.qjc.aop.xml.PersonDaoImpl"></bean>
 <bean id="transaction" class="cn.qjc.aop.xml.Transaction"></bean>

 <aop:config>
  <!-- 切入点表达式 确定目标类 -->
  <aop:pointcut expression="execution(* cn.qjc.aop.xml.PersonDaoImpl.*(..))" id="perform"/>

  <!-- ref指向对象就是切面 -->
  <aop:aspect ref="transaction">
   <aop:before method="beginTransaction" pointcut-ref="perform"/>
   <aop:after-returning method="commit" pointcut-ref="perform"/>
  </aop:aspect>
 </aop:config>

</beans>

测试

/**
 * 测试spring动态代理
 * @author qjc
 */
public class TransactionTest {

 @Test
 public void testSave(){
  ApplicationContext context = new ClassPathXmlApplicationContext("cn/qjc/aop/xml/applicationContext.xml");
  PersonDao personDao = (PersonDao) context.getBean("personDao");
  personDao.savePerson();
 }
}

spring AOP原理

1、当spring容器启动的时候,加载两个bean,对像个bean进行实例化
2、当spring容器对配置文件解析到<aop:config>的时候,把切入点表达式解析出来,按照切入点表达式匹配spring容器内容的bean
3、如果匹配成功,则为该bean创建代理对象
4、当客户端利用context.getBean获取一个对象时,如果该对象有代理对象,则返回代理对象,如果没有代理对象,则返回对象本身

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • spring cglib 与 jdk 动态代理

    1. 概述 JDK动态代理是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理 Cglib动态代理是 利用asm开源包 把被代理类的class文件加载进来 通过修改其字节码生成子类来处理 如果目标对象实现了接口 那么默认使用jdk代理(可以强制使用cglib代理) 如果没有实现接口 必须使用cglib代理 强制使用cglib代理需要 *引入cglibjar包 *配置spring <aop:aspectj-autoproxy proxy-

  • Spring学习之动态代理(JDK动态代理和CGLIB动态代理)

    前言 动态代理,是一种通过运行时操作字节码,以达到增强类的功能的技术,也是Spring AOP操作的基础,关于AOP的内容,将在后面的笔记中详细讲解,本小节主要是理清楚动态代理,毕竟,Spring的AOP是基于动态代理技术,对动态代理技术有所了解,对于学习Spring AOP也会有帮助 动态代理技术详解 动态代理,现在主要是用于增强类的功能,同时由于是具有动态性,所以避免了需要频繁创建类的操作,同时,也使得原有的代码在不需要改变的情况下,对类的功能进行增强,主要的动态代理技术有:通过实现目标接口

  • 利用spring aop实现动态代理

    下面由我来给大家展示用spring aop实现动态代理的例子(电脑打印) 下面就看一下具体的代码: 先定义一个打印机的接口 package aop007_ComPrint; public interface Print { public void ColorPrint(); //彩色打印 public void WhitePrint(); //黑白打印 } 然后定义两个实现类,分别实现彩色打印和黑白打印 package aop007_ComPrint; public class ColorPri

  • spring基础概念AOP与动态代理理解

    一.代理模式 代理模式的英文叫做Proxy或Surrogate,中文都可译为"代理",所谓代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 以简单模拟事务的执行过程说明各种代理区别 1.1 静态代理 由程序员创建或由特定工具自动生成源代码,再对其编译.在程序运行前,代理类的.class文件就已经存在了. public interface PersonDao { vo

  • 深入浅出讲解Spring框架中AOP及动态代理的应用

    目录 一. Spring AOP 1. 传统问题: 2. 问题的解决策略: 3. AOP优点: 二.  动态代理 1.JDK动态代理 2. CGLIB代理 一. Spring AOP 面向切面编程(Aspect Oriented Programming,AOP)是软件编程思想发展到一定阶段的产物,是对面向对象编程(Object Oriented Programming,OOP)的有益补充, 目前已成为一种比较成熟的编程方式.AOP适用于具有横向逻辑的场所,如访问控制.事务管理.性能监测等. 1.

  • Spring基础之AOP的概念介绍

    目录 前言 Spring的AOP的功能和目标 代理方式 @AspectJ的支持 启用@AspectJ 通过Java注解启用AspectJ注解支持: 通过XML配置启用AspectJ注解 定义一个切面 声明一个切入点 常见的切入点匹配表达 切面的增强 前增强BeforeAdvice 后增强 异常增强 环绕增强 代理机制 代理工厂的使用 Spring容器包含两个重要的特性:面向切面编程(AOP)和控制反转(IOC).面向切面编程是面向对象(OOP)的一种补充,在面向对象编程的过程中编程针对的目标是一

  • SpringBoot/Spring AOP默认动态代理方式实例详解

    目录 1. springboot 2.x 及以上版本 2. Springboot 1.x 3.SpringBoot 2.x 为何默认使用 Cglib 总结: Spring 5.x中AOP默认依旧使用JDK动态代理 SpringBoot 2.x开始,AOP为了解决使用JDK动态代理可能导致的类型转换异常,而使用CGLIB. 在SpringBoot 2.x中,AOP如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxy

  • Spring源码学习之动态代理实现流程

    注:这里不阐述Spring和AOP的一些基本概念和用法,直接进入正题. 流程   Spring所管理的对象大体会经过确定实例化对象类型.推断构造方法创建对象(实例化).设置属性.初始化等等步骤.在对象初始化阶段,Spring为开发者提供了一个BeanPostProcessor接口,它会在对象初始化之前和初始化之后被调用(初始化,不是实例化,对应实例化的是InstantiationAwareBeanPostProcessor接口). public interface BeanPostProcess

  • Spring中AOP概念与两种动态代理模式原理详解

    目录 1.概念 1.AOP技术简介 2.AOP的优势 3.Spring AOP术语 4.AOP 开发明确的事项 2.AOP底层实现 1.AOP 的动态代理技术: 3.基于cglib的动态代理代码 总结 1.概念 1.AOP技术简介 AOP 为Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP 是 OOP 的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一

  • Spring AOP注解失效的坑及JDK动态代理

    @Transactional @Async等注解不起作用 之前很多人在使用Spring中的@Transactional, @Async等注解时,都多少碰到过注解不起作用的情况. 为什么会出现这些情况呢?因为这些注解的功能实际上都是Spring AOP实现的,而其实现原理是通过代理实现的. JDK动态代理 以一个简单的例子理解一下JDK动态代理的基本原理: //目标类接口 public interface JDKProxyTestService { void run(); } //目标类 publ

  • Java JDK动态代理(AOP)用法及实现原理详解

    Java-JDK动态代理(AOP)使用及实现原理分析 第一章:代理的介绍 介绍:我们需要掌握的程度 动态代理(理解) 基于反射机制 掌握的程度: 1.什么是动态代理? 2.动态代理能够做什么? 后面我们在用Spirng和Mybatis的时候,要理解怎么使用的. 1.什么是代理? 代理,在我们日常生活之中就有体现,代购,中介,换ip,商家等等. 比如有一家美国的大学,可以对全世界招生.留学中介(代理 ) 留学中介(代理):帮助这家美国的学校招生,中介是学校的代理中介是代替学校完成招生功能 代理特点

  • 关于spring aop两种代理混用的问题

    目录 spring aop两种代理混用问题 一.首先复习一下两种代理 二.我们项目是spring-boot项目 spring的aop和代理模式理解 代理模式代码的主要特点是 代理模式目前实现的方式有三种 Aop的最大意义是 spring aop两种代理混用问题 工作繁忙,但是遇到问题还是要总结积累下来,今天项目中出现了代理混用的问题,解决之后记录一下对两种代理方式的学习理解. 一.首先复习一下两种代理 JDK动态代理 和 cglib代理 1.如果目标对象实现了接口,默认情况下会采用JDK的动态代

随机推荐