代理模式

代理模式_第1张图片

JDK动态代理

一个接口


package _6JDK动态代理;

public interface PersonDao {

	public Object update();
	public void delete();
	public void insert();
}
接口实现类



package _6JDK动态代理;
public class PersonDaoImpl implements PersonDao {
	@Override
	public void delete() {
		// TODO Auto-generated method stub
		System.out.println("delete");
	}
	@Override
	public void insert() {
		// TODO Auto-generated method stub
		System.out.println("insert");
	}
	@Override
	public Object update() {
		// TODO Auto-generated method stub
		System.out.println("update");
		return "update_success";
	}
}
在代理中用来装配的模块



package _6JDK动态代理;
public class Transaction {
	public void beginTransaction(){
		System.out.println("开启事务");
	}
	public void commit(){
		System.out.println("结束事务");
	}
}
在拦截器中装配模块



package _6JDK动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 拦截器
 * @author Think
 *   1、引入目标类
 *   2、引入事务
 *   3、通过构造函数给目标类和事务赋值
 *   4、填充invoke方法
 *
 */
//需要实现InvocationHandler,所以才说是jdk动态代理
public class PersonInterceptor implements InvocationHandler{

	private Object target;//目标类
	private Transaction transsaction;//引入事务
	public PersonInterceptor(Object  target,Transaction transaction){
		this.target = target;
		this.transsaction = transaction;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//在这里把想要组合在一起的内容组合起来
		//只需要组合这一次,以后就不用管了,不像静态代理,每次都要重新写
		//感觉静态代码更像是装饰设计模式
		// TODO Auto-generated method stub
		this.transsaction.beginTransaction();
		//返回的是调用的方法的返回值
		Object message = method.invoke(this.target, args);//调用目标类的方法
		this.transsaction.commit();
		return message;
	}
	
	
}
开始使用代理



package _6JDK动态代理;
import java.lang.reflect.Proxy;
public class test {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Object target = new PersonDaoImpl();
		Transaction transaction = new Transaction();
		PersonInterceptor interceptor 
			= new PersonInterceptor(target, transaction);
		/**
		 * 1、目标类的类加载器
		 * 2、目标类实现的所有的接口
		 * 3、拦截器
		 */
		PersonDao persondao = (PersonDao) Proxy.newProxyInstance(
								target.getClass().getClassLoader(),
								target.getClass().getInterfaces(),
								interceptor);
		System.out.println(persondao.update());
	}
}

JDK的动态代理必须具备四个条件:

目标接口

目标类

拦截器

代理类

总结:

1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有

2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体

     3、利用JDKProxy方式必须有接口的存在

     4invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。


JDK动态代理优化,类似于struts2的拦截器模式。

拦截器接口,用来装配的


package _7JDK动态代理优化;

public interface Interceptor {
	public void interceptor();
}
接口实现,全部是拦截器角色,用来装配的



package _7JDK动态代理优化;

public class Logger implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("logging");
	}
	
}



package _7JDK动态代理优化;

public class Privilege implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("privilege");
	}
	
}
package _7JDK动态代理优化;

public class Security implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("security");
	}
	
}


目标类接口,也就是被代理的类


package _7JDK动态代理优化;

public interface SalaryManager {
	public void showSalary();
}

目标类接口的实现

package _7JDK��̬�����Ż�;

public class SalaryManagerImpl implements 
   SalaryManager {
	public void showSalary() {
		System.out.println("查看工资");
	}
}
目标类和装配模板装配在一起,模板有多个,类似于struts2的拦截器模式

package _7JDK��̬�����Ż�;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

public class SalaryInterceptor implements InvocationHandler{

	
	private Object target;
	
	//把所有切面都放在集合里面    这样�?��改变的也是结合,下面的invoke的切面整合不用因为增加一个�?修改
	private List<Interceptor> interceptors;
	
	public SalaryInterceptor(Object target,List<Interceptor> interceptors){
		this.target = target;
		this.interceptors = interceptors;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		for(Interceptor interceptor:interceptors){
			interceptor.interceptor();
		}
		method.invoke(this.target, args);
		return null;
	}

}
代理测试类:多个拦截器放在集合里面

package _7JDK动态代理优化;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class SalaryTest {
	@Test
	public void test(){
		Object target = new SalaryManagerImpl();
		Logger logger = new Logger();
		Security security = new Security();
		Privilege privilege = new Privilege();
		List<Interceptor> interceptors = new ArrayList<Interceptor>();
		interceptors.add(logger);
		interceptors.add(security);
		interceptors.add(privilege);
		SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
		SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
		salaryManager.showSalary();
	}
}





CGLIB做代理


cglib产生的代理类是目标类的子类,其他和jdk动态代理一样

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

2、 CGlib生成代理类是目标类的子类。

3、 CGlib生成 代理类不需要接口

4、 CGLib生成的代理类重写了父类的各个方法。

5、 拦截器中的intercept方法内容正好就是代理类中的方法体



拦截器接口

package _8cglib动态代理;

public interface Interceptor {
	public void interceptor();
}
实现类

package _8cglib动态代理;

public class Logger implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("logging");
	}
	
}
package _8cglib动态代理;

public class Privilege implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("privilege");
	}
	
}
package _8cglib动态代理;

public class Security implements Interceptor{

	@Override
	public void interceptor() {
		// TODO Auto-generated method stub
		System.out.println("security");
	}
	
}
目标类,和jdk的区别就是这里只有具体类,没有对应的接口

package _8cglib动态代理;

public class SalaryManagerImpl {
	public void showSalary() {
		System.out.println("工资");
	}
}
装配类,装配方式和jdk动态代理有点区别

package _8cglib��̬����;

import java.lang.reflect.Method;
import java.util.List;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class SalaryInterceptor implements MethodInterceptor{

	
	private Object target;
	
	private List<Interceptor> interceptors;
	
	public SalaryInterceptor(Object target,List<Interceptor> interceptors){
		this.target = target;
		this.interceptors = interceptors;
	}
	//固定写法
	public Object createProxy(){
		Enhancer enhancer = new Enhancer();
		enhancer.setCallback(this);
		enhancer.setSuperclass(this.target.getClass());
		return enhancer.create();
	}

	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		// TODO Auto-generated method stub
		for(Interceptor interceptor:interceptors){
			interceptor.interceptor();
		}
		arg1.invoke(this.target, arg2);
		return null;
	}
	

}
代理测试类

package _8cglib动态代理;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class SalaryTest {
	@Test
	public void test(){
		Object target = new SalaryManagerImpl();
		Logger logger = new Logger();
		Security security = new Security();
		Privilege privilege = new Privilege();
		List<Interceptor> interceptors = new ArrayList<Interceptor>();
		interceptors.add(logger);
		interceptors.add(security);
		interceptors.add(privilege);
		SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
		SalaryManagerImpl proxy = (SalaryManagerImpl)interceptor.createProxy();
		proxy.showSalary();
	}
}



JDKCGLIB优缺点

spring有两种代理方式:

1. 若目标对象实现了若干接口,spring使用JDKjava.lang.reflect.Proxy类代理。

      优点:因为有接口,所以使系统更加松耦合

      缺点:为每一个目标类创建接口

2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。

      优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。

      缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。


    总结:不管采用JDK动态代理生成代理类还是采用CGLIB生成动态代理类。目标类中的所有方法都被拦截下来。而在哪个方法里做比如权限的判断、安全性的检查等一系列工做必须在拦截器中作相应的判断。但是这样的编程形式给程序的编写带来了一定的麻烦。

1、 在拦截器中控制哪些方法将被做权限判断、安全性检查等是一件比较困难的事情。

A. 采取这样的配置目标类只能是一个,所以如果用这种方法做权限控制,得写很多代理,这样给代码的书写造成了困难。

B. 每一个类中的每一个方法如果都有不同的权限(实际的系统往往都是这样的),在拦截器中的判断代码书写会很困难。

2、 这样的代码也会导致硬编码,也就是说我们必须在拦截器中写一些权限判断等事情,会导致拦截器中代码量的增大,造成维护的麻烦。

你可能感兴趣的:(代理模式)