本篇记录下spring AOP的两种代理,为下一篇AOP实现做下铺垫。

1.JDK动态代理  2.cglib代理

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

注:JDK动态代理要比cglib代理执行速度快,但性能不如cglib好。所以在选择用哪种代理还是要看具体情况,一般单例模式用cglib比较好,具体原因请自行百度。

一。JDK动态代理实现(原理是使用反射机制)

首先定义接口,并实现

public interface TestService{

public int add();   
      }

public class TestServiceImpl implements TestService{

@Override
         public int add() {
            System.out.println("开始执行add...");
            return 0;
         }
     }

定义代理类,这里要注意导入的包是import java.lang.reflect.*

public class JDKDynamicProxy implements InvocationHandler {

//被代理的目标对象
    private Object proxyObj;  
   
    /**
      * Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
      * loader    :类加载器 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
      * interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
       * h         :一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
     */
       public Object newProxy(Object proxyObj){  
             this.proxyObj = proxyObj;
            //返回一个代理对象  
           return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(),   
                                      proxyObj.getClass().getInterfaces(),   
                                      this);  
       }

/**
       * 执行目标对象
       * Object  proxy:被代理的对象
       * Method  method:要调用的方法
       * Object  args[]:方法调用时所需要的参数
       */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                                   throws Throwable {      
             before();
             Object object = method.invoke(this.proxyObj,args);  // 通过反射机制调用目标对象的方法
             after();      
             return object;  
         }
    
         public void before(){
              System.out.println("开始执行目标对象之前...");
         }
    
         public void after(){
             System.out.println("开始执行目标对象之后...");
         }
     }

测试类:

public static void main(String[] args) {
        
          //我们要代理的真实对象
          TestService testService = new TestServiceImpl();       
          //testJDKProxyService.add();//不是用代理   
        
         JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();
         TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);
         //执行代理类的方法  
         testServiceProxy.add();

}

控制台显示

二。CGLIB代理,需要导入 cglib-nodep-2.1_3.jar

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

先定义一个实现类(注意并没有实现接口)

public class TestCGLIBServiceImpl {

public int add() {
        System.out.println("开始执行add...");
        return 0;
    }
 }

定义cglib代理类,此时导入的包应该是import net.sf.cglib.proxy.*

import java.lang.reflect.Method;
  import net.sf.cglib.proxy.Enhancer;
  import net.sf.cglib.proxy.MethodInterceptor;
  import net.sf.cglib.proxy.MethodProxy;

public class CGLIBProxy implements MethodInterceptor{

private Object targetObject ;//被代理的目标对象
    
    public Object createProxyInstance(Object targetObject) {

this . targetObject = targetObject;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(targetObject.getClass());// 设置代理目标

enhancer.setCallback( this );// 设置回调

return enhancer.create();

}

/**
     * 在代理实例上处理方法调用并返回结果
     * @param object : 代理类
     * @param method :被代理的方法
     * @param args :该方法的参数数组
     * @param methodProxy
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args,
            MethodProxy methodproxy) throws Throwable {       
        Object result = null;    
        try {
              System. out .println( "前置处理开始 ..." );
              result = methodproxy.invoke( targetObject , args);//执行目标对象的方法
              System. out .println( "后置处理开始  ..." );
           } catch (Exception e) {
               System. out .println( " 异常处理 ..." );
           } finally {
               System. out .println( " 调用结束 ..." );
           }
           return result;
       }  
   }
测试类:

public class TestCGLIBProxy {

public static void main(String[] args) {
        
          //我们要代理的真实对象
          TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();
           CGLIBProxy CGLIBproxy = new CGLIBProxy();
           TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);
           testCGLIBProxy.add();
       }
   }

结果图:

写在后面:spring AOP的两种代理实现代码就写到这,这里只是实现了,如果你要想真正明白,还得熟悉其中原理机制,比如反射机制,newProxyInstance(...),Enhancer()原理,invoke()原理等等。

下一篇将要记录spring AOP的基于注解的具体实现,而对于XML的我姑且不是用了,因为不够灵活,不够强大,要是有时间还会介绍下spring AOP 自定义注解的实现

spring AOP的两种代理的更多相关文章

  1. JAVA高级架构师基础功:Spring中AOP的两种代理方式:动态代理和CGLIB详解

    在spring框架中使用了两种代理方式: 1.JDK自带的动态代理. 2.Spring框架自己提供的CGLIB的方式. 这两种也是Spring框架核心AOP的基础. 在详细讲解上述提到的动态代理和CG ...

  2. (一)spring aop的两种配置方式。

    sring aop的方式有两种:(1)xml文件配置方式(2)注解的方式实现,我们可以先通过一个demo认识spring aop的实现,然后再对其进行详细的解释. 一.基于注解的springAop配置 ...

  3. spring AOP的两种配置方式

    连接点(JoinPoint) ,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前.后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点.其他 ...

  4. spring aop的两种写法aspect和advisor

    本文转自:https://www.cnblogs.com/leiOOlei/p/3709607.html 首先看个例子,如下 接口代码: package com.lei.demo.aop.schema ...

  5. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理)

    第一种代理即Java的动态代理方式上一篇已经分析,在这里不再介绍,现在我们先来了解下GCLIB代理是什么?它又是怎样实现的?和Java动态代理有什么区别? cglib(Code Generation ...

  6. Spring中AOP的两种代理方式(Java动态代理和CGLIB代理-转载

    内容是摘抄的,不知最初的原作者,见谅 Java 动态代理.具体有如下四步骤: 通过实现 InvocationHandler 接口创建自己的调用处理器: 通过为 Proxy 类指定 ClassLoade ...

  7. 使用aspectJ实现Spring AOP的两种方式

    方式一:基于aspectJ的XML配置 方式二:基于aspectJ的注解方式 基于aspectJ的XML配置 1)       引入相关jar包 2)       创建Spring核心配置文件,必须导 ...

  8. spring ----> aop的两种实现方式

    实现1:基于xml package com.rr.spring3.interf; //接口 public interface SayHello { public void sayHello(); } ...

  9. spring AOP的两种配置

    xml配置 定义要被代理的方法的接口 public interface TestAop { public void print(String s); } 实现上述接口 public class Tes ...

随机推荐

  1. windows7中的“mklink命令”

    从 Vista 以后,微软将用户文件和用户的软件配置( AppData ) 明确划分开,并且全部存放在使用者的用户目录下. Linux早已这样做了,并且在Linux中可将 home 挂载为独立分区,而 ...

  2. mysql增删改查基本语句

    mysql的增删改查属于基本操作,又被简称CRUD,其中删用的较少,毕竟这个功能给用户是是非常危险的,就是客户删除的数据也没有真正的删除,其中查询是十分常用的. 1 mysql数据库增加:create ...

  3. zabbix修改和查看登录密码

    author:hendsen chen date : 2018-08-30  16:48:18 1,登陆zabbix的服务器,查看zabbix的登陆密码: [root@jason ~]# mysql ...

  4. iOS 8 新特性介绍

    来源:nshipster.cn 发布时间:2014-07-06 阅读次数:2152 随便去问任何人,他们都会告诉你WWDC2014是近年来最为激动的回忆. 整个大会没有发布任何新硬件,它是一次史无前例 ...

  5. shell出现syntax error near unexpected token `<' 解决方法

    最新在看一个shell资料时,按照教材,却出现如下错误,不能运行 如下,简单的脚本: #!/bin/bash cat |while read line do echo $line done < ...

  6. eclipse项目更换svn共享库

    eclipse项目更换svn共享库 参考内容: http://blog.csdn.net/yang5726685/article/details/59111586 已经共享过的svn项目,更换资源库时 ...

  7. 【巷子】---vue路由懒加载---【vue】

    一.懒加载 也叫延迟加载或者按需加载,即在需要的时候进行加载,   二.为什么要使用懒加载 像vue这种单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要 ...

  8. 170503、centos6.5安装mysql5.6.30

    准备:虚拟机地址:192.168.0.110 安装目录/usr/local/ 首先卸载已经安装的mysql使用命令查看rpm -qa | grep mysql卸载使用 rpm -e xxx 或者 yu ...

  9. T-SQL创建作业

    /*1.--创建作业 */ /*--调用示例 --每月执行的作业 exec p_createjob @jobname='mm',@sql='select * from syscolumns',@fre ...

  10. Oracle管理监控 之 rac环境密码文件管理

    密码文件作用: 密码文件用于dba用户的登录认证. dba用户:具备sysdba和sysoper权限的用户,即oracle的sys和system用户. RAC环境中多个节点的密码文件应该保证一致,否则 ...