栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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接口


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();
 }
}

测试


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;


public class Interceptor implements InvocationHandler {

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

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

 
 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;
 }
}

测试


public class TestJDKProxy {
 
 @Test
 public void testSave(){
  
  Object target = new PersonDaoImpl();
  Transaction transaction = new Transaction();
  Interceptor interceptor = new Interceptor(target, transaction);
  
  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;


public class Interceptor implements MethodInterceptor {

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

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

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

 
 public Object intercept(Object obj, Method method, Object[] args,
   MethodProxy methodProxy) throws Throwable {
  this.transaction.beginTransaction();
  method.invoke(target);
  this.transaction.commit();
  return null;
 }
}

测试


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配置

 
 
 
 
  
  
 
  
  
   
   
  
 
 

测试


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容器对配置文件解析到的时候,把切入点表达式解析出来,按照切入点表达式匹配spring容器内容的bean
3、如果匹配成功,则为该bean创建代理对象
4、当客户端利用context.getBean获取一个对象时,如果该对象有代理对象,则返回代理对象,如果没有代理对象,则返回对象本身

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/148832.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号