• 静态代理和利用反射形成的动态代理(JDK动态代理)


    代理模式

    代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    静态代理

    1.新建一个接口,这个接口所提供的方法是关于数据库操作的

    public interface EmployeeDao {
    	public void updateSalary();
    }
    
    

    2.建一个目标类实现这个接口,这个目标类是我们要进行的业务

    public class EmployeeDaoImpl implements EmployeeDao {
    	@Override
    	public void updateSalary() {
    		System.out.println("您的薪水又有更新");
    	}
    }
    
    

    3.再建一个代理类,为目标对象提供一种代理,并以控制对这个对象的访问。

    public class EmployeeDaoProxy implements EmployeeDao{
    	private EmployeeDao employeeDao;
    	private Transaction transaction;
    	public EmployeeDaoProxy(EmployeeDao employeeDao,Transaction transaction) {
    		this.employeeDao=employeeDao;
    		this.transaction=transaction;
    	}
    
    	@Override
    	public void updateSalary() {
    		this.transaction.startTransaction();
    		this.employeeDao.updateSalary();
    		this.transaction.commit();
    	}
    	
    

    由以上的代码可知:

    代理模式的组成包括:目标接口(抽象角色),目标类(真实角色)和代理类(代理角色)。

    • 抽象角色:通过接口声明真实角色实现的业务方法。
    • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
    • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

    4.代理类代理事务的处理,所以需要增加一个事务类

    
    public class Transaction {
    	public void startTransaction(){
    		System.out.println("开启事务");
    	}
        public void commit(){
        	System.out.print("事物提交");
        }
    }
    
    

    5.最后我们用一个test case来测试一下

    
    import static org.junit.Assert.*;
    import org.junit.Test;
    public class ProxyTest {
    	@Test
    	public void test() {
    		EmployeeDao target = new EmployeeDaoImpl();
    		Transaction transaction = new Transaction();
    		EmployeeDao proxy = new EmployeeDaoProxy(target,transaction);
    		proxy.updateSalary();
    	}
    }
    
    
    

    假设上面的例子中的接口不只一个方法,或是不只一个接口要用到代理,上面的静态代理的代码就太过繁琐和冗余,所以就出现了jdk的动态代理。

    看一下执行情况

    开启事务
    您的薪水又有更新
    事物提交
    
    利用反射动态代理

    反射机制指的是程序在运行时能够获取自身的信息。这里的反射一开始不太好理解,其实应该忽略反射的字面意思。只要知道反射其实就是获取Class对象,然后反编译程Java对象,然后访问Java对象的属性、方法等。在Java中,其实所有类的对象都是Class类的实例。每个类被JVM加载之后,就会生成对应对应的Class对象。获得Class对象的方式有以下三种:

    1.使用Class类的forName(String className)静态方法,className为类的全名。

    Class = Class.forName("Employee");
    
    

    2.调用某个类的class属性

    Class = Employee.class
    

    3.调用某个对象的getClass方法

    Employee ee = new Employee();
    Class = ee.getClass();
    

    可以从Class中获取的信息包括:构造器、方法、Annotation、内部类、所实现的接口、所继承的父类、对应类的修饰符,所在包类名等基本信息。除此之外,Class对象还可以判断该类是否为接口、枚举、注解类型。再回到上面的代理模式,在JDK中提供Proxy类和InvocationHandler接口生成JDK动态代理类和动态代理对象,Proxy是所有动态代理类的父类,提供创建动态代理类和代理对象的静态方法。
    1.创建动态代理类的方法

    static Class<?> getProxyClass(ClassLoader loader,Class<?>[]interfaces)
    

    2.创建动态代理实例的方法

    static ObjectnewProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler)
    

    同样以上面的例子做示例,1和2中的接口和目标类的编写以及4中的事务处理是相同的,在3中,我们引入拦截器,拦截器是实现动态性的核心

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /*
     * 拦截器
     * 引入目标类和事务
     * 通过构造器给目标函数和事务赋值
     * 填充invoke方法
     * 
     */
    public class EmployeeInterceptor implements InvocationHandler{
    	private Object target;
    	private Transaction transaction;
    	public EmployeeInterceptor(Object target, Transaction transaction) {
    		
    		this.target = target;
    		this.transaction = transaction;
    	}
    	
    	/*
    	 * proxy:代表动态代理对象
    	 * method:代表正在执行的方法
    	 * args:代表调用方法是传入的参数
    	 */
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		this.transaction.startTransaction();
    		method.invoke(this.target, args);
    		this.transaction.commit();
    		return null;
    	}
    }
    

    同样在test case中测试一下:

    
    import static org.junit.Assert.*;
    import java.lang.reflect.Proxy;
    import org.junit.Test;
    public class ProxyTest1 {
    	@Test
    	public void test() {
    		EmployeeDao target = new EmployeeDaoImpl();
    		Transaction transaction = new Transaction();
    		EmployeeInterceptor interceptor = new  EmployeeInterceptor(target,transaction);
    		//利用Proxy创建动态代理类
    		EmployeeDao  employeeDao = (EmployeeDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
    		employeeDao.updateSalary();
    	}
    }
    
    

    最后看一下执行的情况

    开启事务
    您的薪水又有更新
    事物提交
    
  • 相关阅读:
    DOM对象模型接口规范中的四个基本接口
    js中几种实用的跨域方法原理详解(转)
    关于ie6/7下的z-index
    Mysql++学习(五)------专用SQL结构
    Mysql++学习(四)------模板查询
    Mysql++学习(三)------举个栗子
    Mysql++学习(二)------Mysql++简述
    Mysql++学习(一)------mysql编译安装
    epoll模型实例
    锁、页类型
  • 原文地址:https://www.cnblogs.com/sweiqi/p/5933743.html
Copyright © 2020-2023  润新知