静态代理和利用反射形成的动态代理(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();
	}
}

最后看一下执行的情况

开启事务
您的薪水又有更新
事物提交
原文地址:https://www.cnblogs.com/sweiqi/p/5933743.html