一.AOP的概念

 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

二.主要用途

将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

  三.代理

 AOP的实现关键在于AOP框架自动创建的AOP代理。AOP代理主要分为两大类:

         1.静态代理:使用AOP框架提供的命令进行编译,从而在编译阶段就可以生成AOP代理类,因此也称为编译时增强;静态代理一Aspectj为代表。

         2.动态代理:在运行时借助于JDK动态代理,CGLIB等在内存中临时生成AOP动态代理类,因此也被称为运行时增强,Spring AOP用的就是动态代理。

         那么其实在Spring框架中用到就是JDK动态代理或者是CGLIB代理。

四.JDK动态代理

        JDK动态代理用到了一个类Proxy,下面举个例子来说明一下,Proxy这个类是如何实现JDK的动态代理的。

          有一个需求就是,当用户名为空的时候,不能调用业务方法,当用户名不为空是可以调用业务方法。

          1.新建一个业务接口,并书写业务方法。

           

package cn.service;

public interface DoService {
    //添加
    public void  add();
    //查询
    public void selectInfo();
    //更新
    public void update();
}

2.新建一个业务接口实现类

package cn.service.impl;

import cn.service.DoService;

public class DoServiceImpl implements DoService{

    //用户名
    private String userName;

    @Override
    public void add() {
        System.out.println("添加的方法");

    }

    @Override
    public void selectInfo() {
        System.out.println("查询的方法");

    }

    @Override
    public void update() {
        System.out.println("更新的方法");
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

}

 一般如果我们需要进行这样一个业务需求我们会相到 一个办法就是在所有的方法中进行一个判断就是判读用户名是否为空,显然这样很麻烦,所有我们用到了JDK动态代理,主函数 -->代理-->目标对象的方法。这样,以后不管是修改判断条件,还是查找等,可以直接在代理类中进行处理。

           

3.创建代理对象工厂类

         

package cn.aop;

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

import cn.service.impl.DoServiceImpl;

/**
 * 代理工厂类
 * @author hyj
 *
 */
public class JDKProxyFactory implements InvocationHandler{
    //要返回的代理对象
   private Object obj;
   /**
    * 通过代理工厂的方式来创建代理类
    * @param obj  要代理的类的对象
    * @return
    */
   public Object createProxyIntance(Object obj){
       this.obj=obj;
       //第一个参数是目标对象的类加载器
       //第二个参数是目标对象实现的接口
       //第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
       return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),this);

   }
   @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
       Object proxyObject=null;
       DoServiceImpl ds=(DoServiceImpl)obj;
       if(ds.getUserName()!=null){
           proxyObject= method.invoke(ds, args);
       }else{
           System.out.println("用户名为空,已拦截");
       }
        return proxyObject;
    }
    public Object getObj() {
        return obj;
    }
    public void setObj(Object obj) {
        this.obj = obj;
    }

}

4.测试类

package cn.test;

import cn.aop.JDKProxyFactory;
import cn.service.DoService;
import cn.service.impl.DoServiceImpl;

public class TestHappy {
   public static void main(String[] args) {
      JDKProxyFactory jpf=new JDKProxyFactory();
      DoService ds=(DoService)jpf.createProxyIntance(new DoServiceImpl("fsf"));
      ds.selectInfo();
   }
}

     步骤:

  • 首先调用代理工厂的createProxyIntance(Object obj)创建DoServiceImpl类的代理类.
  • 在该方法内,调用Proxy.newProxyInstance()方法创建代理对象。第一个参数是目标对象的类加载器,第二个参数是目标对象实现的接口,第三个参数传入一个InvocationHandler实例,该参数和回调有关系。
  • 每当调用目标对象的方法的时候,就会回调该InvocationHandler实例的方法,也就是public Object invoke()方法,我们就可以把限制的条件放在这里,条件符合的时候,就可以调用method.invoke()方法真正的调用目标对象的方法,否则,则可以在这里过滤掉不符合条件的调用。

        五.CGLIB代理

       在这一步中,我们使用一个Enhancer类来创建代理对象,不再使用Proxy。使用Enhancer类,需要为其实例指定一个父类,也就是我们 的目标对象。这样,我们新创建出来的对象就是目标对象的子类,有目标对象的一样。除此之外,还要指定一个回调函数,这个函数就和Proxy的 invoke()类似。

总体来说,使用CGlib的方法和使用Proxy的方法差不多,只是Proxy创建出来的代理对象和目标对象都实现了同一个接口。而CGlib的方法则是直接继承了目标对象。

1.引入jar包

 

2.创建CGLIB实现代理的类

package cn.aop;

import java.lang.reflect.Method;

import cn.service.impl.DoServiceImpl;

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

/**
 * CGLIB实现代理
 * @author hyj
 *
 */
public class CGLIBProxyFactory implements MethodInterceptor {
    //要放回的代理对象
     private Object obj;
     public Object createProxy(Object obj){
         //把传进来的代理对象赋值给obj
         this.obj=obj;
         Enhancer enhancer = new Enhancer();
         //需要为其实例指定一个父类,也就是我们 的目标对象,那么我们新创建出来的对象就是目标对象的子类,有目标对象的一样
         enhancer.setSuperclass(this.obj.getClass());
         //除此之外,还要指定一个回调函数,这个函数就和Proxy的 invoke()类似
         enhancer.setCallback(this);
         return enhancer.create();   

     }
    @Override
    public Object intercept(Object object, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {
          Object proxyObject=null;
           DoServiceImpl ds=(DoServiceImpl)obj;
           if(ds.getUserName()!=null){
               proxyObject= methodProxy.invoke(ds, args);
           }else{
               System.out.println("用户名为空,已拦截");
           }
            return proxyObject;
    }

}

测试类 

   

 @Test
   public void CGLIBProxyTest(){
       CGLIBProxyFactory gb=new CGLIBProxyFactory();
       DoServiceImpl ds= (DoServiceImpl)gb.createProxy(new DoServiceImpl("sf"));
       ds.add();
   }

基于Spring AOP的JDK动态代理和CGLIB代理的更多相关文章

  1. 设计模式---JDK动态代理和CGLIB代理

    Cglig代理设计模式 /*测试类*/ package cglibProxy; import org.junit.Test; public class TestCglib { @Test public ...

  2. JDK动态代理和 CGLIB 代理

    JDK动态代理和 CGLIB 代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期期间创建一个接口的实现类来完成对目标对象的代理. 代码示例 接口 public interface ...

  3. JDK动态代理和CGLIB代理的区别

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  4. 动态代理:JDK动态代理和CGLIB代理的区别

    代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JD ...

  5. JDK动态代理和cglib代理详解

    JDK动态代理 先做一下简单的描述,通过代理之后返回的对象已并非原类所new出来的对象,而是代理对象.JDK的动态代理是基于接口的,也就是说,被代理类必须实现一个或多个接口.主要原因是JDK的代理原理 ...

  6. JDK动态代理和cglib代理

    写一个简单的测试用例,Pig实现了Shout接口 public class MyInvocation implements InvocationHandler { Object k; public M ...

  7. SpringAOP-JDK 动态代理和 CGLIB 代理

    在 Spring 中 AOP 代理使用 JDK 动态代理和 CGLIB 代理来实现,默认如果目标对象是接口,则使用 JDK 动态代理,否则使用 CGLIB 来生成代理类. 1.JDK 动态代理 那么接 ...

  8. 静态代理、动态代理和cglib代理

    转:https://www.cnblogs.com/cenyu/p/6289209.html 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处 ...

  9. 基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别。

    基于JDK动态代理和CGLIB动态代理的实现Spring注解管理事务(@Trasactional)到底有什么区别. 我还是喜欢基于Schema风格的Spring事务管理,但也有很多人在用基于@Tras ...

随机推荐

  1. USACO . Friday the Thirteenth

    Friday the Thirteenth Is Friday the 13th really an unusual event? That is, does the 13th of the mont ...

  2. 《使用Hibernate开发租房系统》内部测试笔试题

    笔试总结 1.在Hibernate中,以下关于主键生成器说法错误的是( C). A.increment可以用于类型为long.short或byte的主键 B.identity用于如SQL Server ...

  3. [No0000AA]Windows 系统环境变量列表

    环境变量 详细信息 %ALLUSERSPROFILE% 所有用户 Profile 文件位置 %APPDATA% 应用程序数据的默认存放位置 %CD% 当前目录 %CLIENTNAME% 联接到终端服务 ...

  4. HackerRank Week of Code 26

    好像这次week of code不是很难= = A int main(){ int n; int m; cin >> n >> m; cout<<(n+)/*)/) ...

  5. Paxos

    Paxos算法原理与推导   Paxos算法在分布式领域具有非常重要的地位.但是Paxos算法有两个比较明显的缺点:1.难以理解 2.工程实现更难. 网上有很多讲解Paxos算法的文章,但是质量参差不 ...

  6. jQuery Ajax传值给Servlet,在Servlet里Get接受参数乱码的解决方法

    最近在学jquery ui,在做一个小功能的时候需要将前台的值获取到,通过Ajax传递给Servlet,然后再在返回数据结果,但是在Servlet接受参数的时候,通过后台打印,发现接受乱码,代码示例如 ...

  7. SQL基础语法(二)

    SQL SELECT 语句 本章讲解 SELECT 和 SELECT * 语句. SQL SELECT 语句 SELECT 语句用于从表中选取数据. 结果被存储在一个结果表中(称为结果集). SQL ...

  8. PHP执行文档操作

    1.POWINTPOINT系列 之前参与过一个商城的项目,里面有将excel 导出的功能,但是如果要弄成PPT的我们应该怎么办呢?PHP是属于服务器端的 总不能在里面装个Powintpoint吧.于是 ...

  9. 织梦多语言站点,{dede:include filename=''/}引入问题

    织梦模板include插入非模板目录文件出现"无法在这个位置找到"错误的解决办法 以下是dede V55_UTF8 查dede include标签手册 (3) include 引入 ...

  10. phpcms二次开发中无法获取SESSION的值

    今天在在phpcms开发留言板用到验证码,提交数据,后台无法$_SESSION['code']无法获取验证码值,也无法打印var_dump($_SESSION)值,我们只需要在文件头部添加如下代码: ...