Coin163

首页 > Spring AOP(2)动态代理

Spring AOP(2)动态代理

相关标签: jdk spring aop

2020腾讯云双十一活动,全年最低!!!(领取3500元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1074

【阿里云】双十一活动,全年抄底价,限时3天!(老用户也有),
入口地址https://www.aliyun.com/1111/home

相关推荐:Spring系列之Java代理机制实现AOP

    【回顾】     在之前的学习中,我们对Spring框架有了一个宏观认识,并且深入分析学习了它的核心内容IOC。从这篇博客,将开始对其另一个重要思想的实现展开学习,那就是AOP。    【前言】    AOP的意思是面向切面编程,英文全称是Aspect Oriented Progra

上篇文章使用了静态代理机制,其实这样并不好,会造成代码冗余。例如日志代理,很多地方都需要用到日志代理,但是静态代理,需要有真实类(目标类target)的引用,就把代理和目标类绑定了。即,产品的日志代理只能在产品类中使用,不能在工厂类中使用。为了解决这一问题,就用到动态代理机制。动态代理有很多方法,如JDK动态代理Cglib动态代理,今天就JDK以JDK动态代理为例。
JDK动态代理的原理,是代理类实现InvocationHandler接口,有Proxy来完成代理类的创建。当调用目标类的方法,就会调用代理类的invoke方法在invoke方法中加入增强
代码如下:
目标类的接口

package com.yc.biz;

public interface ProductBiz {
    public void addProduct();
}

目标类的实现

package com.yc.biz.impl;

import com.yc.biz.ProductBiz;

public class ProductBizImpl implements ProductBiz {

    public void addProduct() {
        System.out.println("**********************************");
        System.out.println("添加产品");
        System.out.println("**********************************");

    }

}

代理类,校验代理:

package com.yc.advice;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这个类是切面,完成的功能是向目标方法加入功能(增强)
public class RightAdvice implements InvocationHandler{
    private Object obj;

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        check();
        Object object=method.invoke(obj, args);
        System.out.println(object);
        return object;
    }
    public Object createInstance(Object targetObject){
        this.obj=targetObject;
        //目标对象生成代理对象
        //生成的代理对象,是根据目标对象的借口生成的
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
        //客户端调用createInstance得到一个代理对象,再调用这个代理对象的方法。-》自动加载调用(this)-》invoke
    }

    private void check(){
        System.out.println("*****************************");
    }

}

测试类:

package com.yc.test;

import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
import com.yc.biz.ProductBiz;
import com.yc.biz.StudentBiz;
import com.yc.biz.impl.ProductBizImpl;
import com.yc.biz.impl.StudentBizImpl;

public class Test2 {

    /** * @param args */
    public static void main(String[] args) {
        RightAdvice ra=new RightAdvice();
        ProductBiz pb=new ProductBizImpl();
        ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb);
        productBizProxy.addProduct();

    }

}
测试结果
权限
*****************************
**********************************
添加产品
**********************************

JDK动态代理也是面向接口的,也支持多重代理
日志代理代码:

package com.yc.advice;

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

public class LogAdvice implements InvocationHandler {

    private Object obj;
    /*public RightAdvice(Object targetObject){ this.obj=targetObject; }*/
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        Object object=method.invoke(obj, args);
        log(obj, method, args);
        return object;
    }
    public Object createInstance(Object targetObject){
        this.obj=targetObject;
        //目标对象生成代理对象
        //生成的代理对象,是根据目标对象的借口生成的
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
        //客户端调用createInstance得到一个代理对象,再调用这个代理对象的方法。-》自动加载调用(this)-》invoke
    }

    private void log(Object obj, Method method, Object[] args){
        System.out.println("*****************************");
        System.out.println("操作时间:"+new Date());
        System.out.println("调用的目标类是:"+obj.getClass().getName());
        System.out.println("调用的方法是:"+method.getName());
        System.out.println("参数值:+");
        if(args!=null){
            for(Object arg:args){
                System.out.println(arg);
            }
        }
        System.out.println("*****************************");
    }

}

测试代码如下

相关推荐:spring的aop 基于schema

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程 一 前期工作 1.新建一个java项目,我是使用的maven,所以我新建了一个简单的maven项目,因为maven项目可以省去到处找jar包的时间,还是比较方便的 2.引入需要的jar包,我的pom文件中的dependency

package com.yc.test;

import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
import com.yc.biz.ProductBiz;
import com.yc.biz.StudentBiz;
import com.yc.biz.impl.ProductBizImpl;
import com.yc.biz.impl.StudentBizImpl;

public class Test2 {

    /** * @param args */
    public static void main(String[] args) {
        RightAdvice ra=new RightAdvice();
        ProductBiz pb=new ProductBizImpl();
        ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb);
        LogAdvice la=new LogAdvice();
        //代理了校验代理类
        ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy);
        productBizProxy2.addProduct();

    }

}

利用代理代理学生类:
学生类接口:

package com.yc.biz;

public interface StudentBiz {
    public void findAll();
}

实现:

package com.yc.biz.impl;

import com.yc.biz.StudentBiz;

public class StudentBizImpl implements StudentBiz {

    public void findAll() {
        System.out.println("查找所有学生");

    }

}

测试:

package com.yc.test;

import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
import com.yc.biz.ProductBiz;
import com.yc.biz.StudentBiz;
import com.yc.biz.impl.ProductBizImpl;
import com.yc.biz.impl.StudentBizImpl;

public class Test2 {

    /** * @param args */
    public static void main(String[] args) {
        RightAdvice ra=new RightAdvice();
        ProductBiz pb=new ProductBizImpl();
        ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb);
        //productBizProxy.addProduct();
        LogAdvice la=new LogAdvice();
        ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy);
        productBizProxy2.addProduct();
        StudentBiz sb=new StudentBizImpl();
        StudentBiz studentBizRightProxy=(StudentBiz) ra.createInstance(sb);
        studentBizRightProxy.findAll();

    }

}

当然,看到这个例子,你们可能有疑问,当代理类调用方法时,是如何调用invoke方法的,如果只是应用的话,上面的注释够用了,如果是底层,我觉得是通过某种机制,通知了代理类的invoke方法,因为代理类的实例中有this参数即是代理。具体怎么实现我目前尚不太清楚

使用JDK动态代理时可能遇到的问题,当你用下面的测试方式:
测试代码:

package com.yc.test;

import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
import com.yc.biz.ProductBiz;
import com.yc.biz.StudentBiz;
import com.yc.biz.impl.ProductBizImpl;
import com.yc.biz.impl.StudentBizImpl;

public class Test2 {

    /** * @param args */
    public static void main(String[] args) {
        RightAdvice ra=new RightAdvice();
        ProductBiz pb=new ProductBizImpl();
        ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb);
        //productBizProxy.addProduct();
        LogAdvice la=new LogAdvice();
        ProductBiz productBizProxy2=(ProductBiz) la.createInstance(productBizProxy);
        productBizProxy2.addProduct();
        StudentBiz sb=new StudentBizImpl();
        StudentBiz studentBizRightProxy=(StudentBiz) ra.createInstance(sb);
        studentBizRightProxy.findAll();
        ProductBiz productBizProxy3=(ProductBiz) la.createInstance(productBizProxy);
        productBizProxy3.addProduct();

    }

}
会报错
Exception in thread "main" java.lang.reflect.UndeclaredThrowableException(简单引用)
这是因为,代理也是引用机制,同一个代理,代理不同的目标类,只有一个代理引用,所以当ra代理过StudentBIz后,再用ProductBiz productBizProxy3=(ProductBiz) la.createInstance(productBizProxy);时出错,解决方法就是,不要再用引用,重新new一个代理即可修改如下
ProductBiz productBizLogProxy=(ProductBiz) la.createInstance(ra.createInstance(pb));

源代码下载地址http://download.csdn.net/detail/growing_it_bird/8978017

原文

上篇文章使用了静态代理机制,其实这样并不好,会造成代码冗余。例如日志代理,很多地方都需要用到日志代理,但是静态代理,需要有真实类(目标类target)的引用,就把代理和目标类绑定了。即,

------分隔线----------------------------