静态代理、动态代理、Cglib代理全面梳理

版权声明:未经本人同意,不得私自转载 https://blog.csdn.net/weixin_41866744/article/details/83047176

1.1   代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式;即通过代理访问目标对象。 这样好处: 可以在目标对象实现的基础上,增强额外的功能操作。(扩展目标对象的功能)。

举例:明星(邓紫棋)<-----经纪人<-------用户 

             目标                      (代理)

代理模式的关键点: 代理对象与目标对象。

1.2  静态代理

静态代理,

         1) 代理对象,要实现与目标对象一样的接口;

         2) 举例:

                            保存用户(模拟)

                                     Dao  ,  直接保存

                                     DaoProxy, 给保存方法添加事务处理

//接口类
public interface UserDao {
	//保存方法
	void save();
}


/**
 * 目标对象
 */
public class UserDaoImpl implements UserDao{

	@Override
	public void save() {
		System.out.println("----------已保存数据----------");
	}
}


/**
 * 代理对象(静态代理)
 * 		代理对象要实现与目标对象一样的方法
 */
public class UserDaoImplProxy implements UserDao{

	//接受保存目标对象
	public UserDao target;
	
	public UserDaoImplProxy(UserDao target){
		this.target = target;
	}

	@Override
	public void save() {	//开闭原则
		System.out.println("开启事务");
		target.save();
		System.out.println("结束事务");
	}
}


//测试类
public class App {
	public static void main(String[] args) {
		//目标对象
		UserDao target = new UserDaoImpl();
		//代理对象
		UserDao proxy = new UserDaoImplProxy(target);
		proxy.save();	//执行代理方法
	}
}

输出结果:
        
        开启事务
        ----------已保存数据----------
        结束事务

总结静态代理:

         1)可以做到在不修改目标对象的功能前提下,对目标对象功能扩展。

         2)缺点:

                   --》  因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多。

                   --》  一旦接口增加方法,目标对象与代理对象都要维护。

解决:

         代理工厂?  可以使用动态代理。

1.3  动态代理

动态代理,

         1)代理对象,不需要实现接口;

         2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型;);

         3)  动态代理, JDK代理, 接口代理;

 

JDK中生成代理对象的API:

|-- Proxy

         static Object newProxyInstance(

ClassLoader loader,       指定当前目标对象使用类加载器

 Class<?>[] interfaces,     目标对象实现的接口的类型

InvocationHandler h       事件处理器

//接口类
public interface UserDao {
	void save();
}


/**
 * 目标对象
 */
public class UserDaoImpl implements UserDao{
	@Override
	public void save() {
		System.out.println("----------已保存数据----------");
	}
}


//动态代理工厂
/**
 * 给所有的Dao创建代理对象【动态代理】
 * 代理对象 不需要实现接口 指定目标对象使用的接口类型即可
 */
public class ProxyFactory {
	
	//维护一个目标对象
	private Object target;
	
	public ProxyFactory(Object target){
		this.target = target;
	}

	//给目标对象生成代理对象
	public Object getProxyInstance(){
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(), 	//类加载器
				target.getClass().getInterfaces(),		//得到目标对象实现的接口 进行指定 		
				new InvocationHandler() {				//事件处理器
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("开启事务");
						//执行目标对象方法
						Object returnValue = method.invoke(target, args);
						
						System.out.println("提交事务");
						return returnValue;
					}
				});		
	}
}


//测试类
public class App {
	public static void main(String[] args) {
		//目标对象
		UserDao target = new UserDaoImpl();
		//原始类型【com.tao.dynamicProxy.UserDaoImpl】
		System.out.println(target);
		
		//静态代理对象
		//UserDao proxy = new UserDaoImplProxy(target);
		//proxy.save();	//执行代理方法
			
		//动态代理工厂 给目标对象 创建代理对象
		UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
		//代理类型【class com.sun.proxy.$Proxy0】	内存中动态生成的代理对象
		System.out.println(proxy.getClass());
		proxy.save();
		
	}
}


输出结果:
            
            com.tao.dynamicProxy.UserDaoImpl@8523ca2
            class com.sun.proxy.$Proxy0
            开启事务
            ----------已保存数据----------
            提交事务

动态代理总结:

         代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理!
         (class  $Proxy0  implements IuserDao)

 

思考:

         有一个目标对象,想要功能扩展,但目标对象没有实现接口,怎样功能扩展?

         Class  UserDao{}

         // 子类的方式

         Class subclass  extends  UserDao{}         

         以子类的方式实现(cglib代理)

1.4  Cglib代理

Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。

 

  1. JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
  2.   CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

 CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

 

Cglib子类代理:

         1) 需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。

         2)引入功能包后,就可以在内存中动态构建子类

         3)代理的类不能为final, 否则报错。

         4) 目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法。

        

在Spring的AOP编程中,

         如果加入容器的目标对象有实现接口,用JDK代理;

         如果目标对象没有实现接口,用Cglib代理;

/**
 * 目标对象
 */
public class UserDao {
	public void save(){
		System.out.println("---- 已经保存数据 ----");
	}
}


/**
 * Cglib子类代理工厂
 * 对userDao 在内存中动态构建一个子类对象
 *
 */
public class CglibProxyFactory implements MethodInterceptor{

	//维护一个目标对象
	private Object target;
	public CglibProxyFactory(Object target){
		this.target = target;
	}
	
	//给目标对象创建代理对象 
	public Object getProxyInstance(){
		//1.工具类
		Enhancer en = new Enhancer();
		//2.设置父类
		en.setSuperclass(target.getClass());
		//3.设置回调函数
		en.setCallback(this);
		//4.创建子类(代理对象)
		return en.create();
	}
	
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

		System.out.println("开始事务...");
		
		//执行目标对象的方法
		Object returnValue = method.invoke(target, args);
		
		System.out.println("提交事务...");
		
		return returnValue;
	}

}


//测试类
public class App {
	public static void main(String[] args) {
		//目标对象
		UserDao target = new UserDao();
		
		//代理对象
		UserDao proxy = (UserDao) new CglibProxyFactory(target).getProxyInstance();
		
		//执行代理对象的方法
		proxy.save();
	}
}


//输出结果:

            开始事务...
            ---- 已经保存数据 ----
            提交事务...

猜你喜欢

转载自blog.csdn.net/weixin_41866744/article/details/83047176