深入浅出Java动态代理和静态代理

图示:

概述:

·代理模式(Proxy Pattern):是23种设计模式中的一种,属于结构型的模式。指一个对象本身不做实际的操作,而是通过其它对象来得到自己想得到的结果

·意义:目标对象只需要关心自己的实现细节,通过代理对象来实现功能的增强,可以扩展目标对象的功能。

·体现了非常重要的编程思想:不能随便修改源码,如果需要修改源码,通过修改代理的方式来实现功能的拓展。

二、如何实现代理:

图示:

元素组成:
接口:定义行为和规范

被代理类:是目标对象
代理类:功能增强

静态代理:

创建domain对象

/**
 * 学生类
 */
@Data
public class Student {
    private String name;
    private Integer age;
}

创建service 接口 定义规范

public interface IStudentService {
    /**
     * 添加学生
     */
    void save();

    /**
     * 查询学生信息
     * @param id
     * @return
     */
    Student query(long id);

}

创建实现类,创建被代理类


/**
 * 被代理类
 */
public class StudentServiceImple implements IStudentService {
    @Override
    public void save() {
        System.out.println("保存学生信息");
    }

    @Override
    public Student query(long id) {
        Student student=new Student();
        student.setName("Colie");
        student.setAge(18);
        return student;
    }
}

创建事务类

public class DaoTransaction {
    public void before(){
        System.out.println("开启事务操作");
    }
    public void after(){
        System.out.println("关闭事务");
    }

创建代理增强类对象

public class ProxyStudent implements IStudentService {
    //目标类对象
    private StudentServiceImple studentServiceImple;
    //需要做的增强对象
    private DaoTransaction daoTransaction;

    //通过构造器实现目标类和增强类
    public  ProxyStudent(StudentServiceImple studentServiceImple,DaoTransaction daoTransaction){
        this.studentServiceImple=studentServiceImple;
        this.daoTransaction=daoTransaction;
    }

    @Override
    public void save() {
       //开启事务操作
        daoTransaction.before();
        //目标类的操纵
        studentServiceImple.save();
        //关闭事务操作
        daoTransaction.after();

    }

    @Override
    public Student query(long id) {
        return studentServiceImple.query(id);
    }
}

测试代理类对象;

public class TestStudent {
    @Test
    public void testStudent(){
        DaoTransaction transaction=new DaoTransaction();
        StudentServiceImple studentServiceImple = new StudentServiceImple();
        //获取代理类对象
        //包含木匾对象一级潜质通知和后置通知
        ProxyStudent proxyStudent = new ProxyStudent(studentServiceImple,transaction);//构造方法
        proxyStudent.save();
        proxyStudent.query(1L);
    }
}

实现结果:
 

静态代理的一些问题:

1.静态代理不利于代码的拓展,比如接口中心仪安家以后哥抽象方法时,所实现类都需要重新实现,否则报错

2.代理对象需要创造很多,这种设计很不方便和麻烦。

三:动态代理

1.概述

·概述:在不改变原有功能代码的前提下,能够动态的实现方法的增强

2.JDK动态代理

基础准备

创建Service接口

public interface IStudentService {
    /**
     * 添加学生
     */
    void save();

    /**
     * 查询学生信息
     * @param id
     * @return
     */
    Student query(long id);

//    Student delete();

}

创建Service实现类:(需要代理的类)

public class StudentServiceImple implements IStudentService {
    @Override
    public void save() {
        System.out.println("保存学生信息");
    }

    @Override
    public Student query(long id) {

        System.out.println("查询方法-----------");
        Student student=new Student();
        student.setName("Colie");
        student.setAge(18);
        return student;
    }


}

增强类:

public class DaoTransaction {
    public void before(){
        System.out.println("开启事务操作");
    }
    public void after(){
        System.out.println("关闭事务");
    }

}

2.2实现InvocationHandler接口

实现接口

public class TransasctionHandler implements InvocationHandler {
    //增强类对象
    private DaoTransaction daoTransaction;
    //需要代理的目标对象
    private Object obj;

    public TransasctionHandler(DaoTransaction daoTransaction,Object obj){
        this.obj=obj;
        this.daoTransaction=daoTransaction;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object responce=null;
        //判断当前方法是否是save ,是才做事务操作
        if ("save".equals(method.getName())) {
            daoTransaction.before();
            responce = method.invoke(obj, args);
            daoTransaction.after();
        }else {
            responce=method.invoke(obj,args);
        }

        return responce;

    }
}

分别介绍里面的参数:

proxy:代理实例。可以通过newProxyInstance创建代理实例

    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

ClassLoader loader:

类加载器,直接通过需要代理的类获取就行-(StudentServiceImple.class.getClassLoader()

Class<?>[] interfaces:目标类所实现下的所有接口(StudentServiceImple.class.getInterfaces())
InvocationHandler h:方法拦截器,可以在里面实现方法的增强(transasctionHandler)

Method:执行目标方法的,invoke 执行

args :参数数组

测试类:

public class TestStudent {
    @Test
    public void testStudent(){
        //增强类对象
        DaoTransaction transaction=new DaoTransaction();
        //目标执行类
        StudentServiceImple studentServiceImple = new StudentServiceImple();
        //方法拦截处理器
        TransasctionHandler transasctionHandler=new TransasctionHandler(transaction,studentServiceImple);
        //获取代理对象实例
        IStudentService iStudentService = (IStudentService)Proxy.newProxyInstance(StudentServiceImple.class.getClassLoader(),
                StudentServiceImple.class.getInterfaces(),transasctionHandler);
        iStudentService.save();
        iStudentService.query(1L);
    }
}

2.4底层运行原理

生成代理类的字节码,原理图:

文字说明:

  • 通过实现接口,获取到接口里面的所有方法
  • 通过Proxy创建代理类实例
  • 通过反射机制,获取到一个个的方法对象
  • 调用InvocationHandler接口中的invoke方法,从而实现业务的增强

3.CGLIB动态代理

·JDK动态代理有一个前提,需要代理的类必须实现接口,如果没有实现接口,只能通过CGLB来实现,其实就是对于DK动态代理的一个补充

导包:


        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

准备好目标类

public interface IStudentService {
    /**
     * 添加学生
     */
    void save(Student student);

    /**
     * 查询学生信息
     * @param id
     * @return
     */
    Student query(long id);
}
public class StudentServiceImple implements IStudentService {
    @Override
    public void save(Student student) {
        System.out.println("保存学生信息");
    }

    @Override
    public Student query(long id) {

        System.out.println("查询方法-----------");
        Student student=new Student();
        student.setName("Colie");
        student.setAge(18);
        return student;
    }
}
实现方法拦截:
public class CglibIntercepter implements MethodInterceptor {
    DaoTransaction transaction;
//    IStudentService studentService;
    public  CglibIntercepter( DaoTransaction transaction){
//        this.studentService=studentService;
        this.transaction=transaction;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //事务增强
        transaction.before();
        Object res = methodProxy.invokeSuper(o, objects);
        transaction.after();
        return res ;

    }
}
测试类:

    @Test
    public void testStudent() {
    //得到方法拦截器
        CglibIntercepter cglibIntercepter = new CglibIntercepter(new DaoTransaction());
        //使用Cglib 框架生成目标类的子类(代理类)实现增强
        Enhancer enhancer=new Enhancer();
        //设置父类字节码
        enhancer.setSuperclass(StudentServiceImple.class);
        //设置拦截处理
        enhancer.setCallback(cglibIntercepter);
        IStudentService service=(IStudentService) enhancer.create();
        service.save(new Student());

    }
底层运行原理图:


·文字说明:

  • 通过继承的方式去获取到目标对象的方法
  • 通过传递方法拦截器MethodInterceptor实现方法拦截,在这里面做具体的增强
  • 调用生成的代理类对象具体执行重写的save方法,直接去调用方法拦截器里面的intercept方法
  • 前后加上了增强操作,从而实现了不修改目标代码实现业务增强

总结:
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值