细说java动态代理和cglib的动态代理

          提到代理,想必大家对设计模式中的静态代理和动态代理都比较熟悉,小编之前在博客中对动态和静态代理进行了对比,这篇博文就只探讨java动态代理和cglib动态代理之间的区别;

♚  静态代理的温习

        在我们使用静态代理的时候,每一个代理类只能为一个接口提供服务,这这样一来在程序开发中会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外,其他的操作都是相同的,这样就会造成过多的重复代码;

       为了解决上述问题,我们使用一个代理类来完成所有的代理功能,而这就需要引入动态代理;

♚  动态代理

       与静态代理相对的是动态代理,动态代理类的字节码在程序运行时由java反射机制动态生成,无需程序员手工编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为java反射机制可以生成任意类型的动态代理类。

      下面我们以一个示例来说明动态代理:该示例中以一个checkSecurity()的例子来演示动态代理:

UserManager.java:

package com.ysc.spring;

/**
 * 要实现的接口
 * @author root
 *
 */
public interface UserManager {
	
	public void addUser(String username,String password);
	
	public void delUser(int userId);
	
	public String findUserById(int userId);
	
	public void modifyUser(int userId,String username,String passwordString);
}

UserManagerImpl.java

package com.ysc.spring;

public class UserManagerImpl  implements UserManager {

	@Override
	public void addUser(String username, String password) {
		//checkSecurity();
		System.out.println("-------------userManager.add()---------");
	}

	@Override
	public void delUser(int userId) {
		//checkSecurity();
		System.out.println("-------------userManager.delUser()---------");
	}
		
	@Override
	public String findUserById(int userId) {
		//checkSecurity();
		System.out.println("-------------userManager.findUserById()---------");
		return "张三";
	}

	@Override
	public void modifyUser(int userId, String username, String passwordString) {
		//checkSecurity();
		System.out.println("-------------userManager.modifyUser()---------");
	}
	
}

     由于检查安全性的方法是可以独立于当前接口中其他业务方法的,所以我们可以把这个独立的服务拿出来,放到一个代理类中,使用动态代理把检查安全性的方法动态的加入到每一个方法中,而这些代理的工作需要由一个单独的代理类来完成:

SecurityHandler.java:

package com.ysc.spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SecurityHandler implements InvocationHandler {

	private Object targetObject;
	
	public Object createProxyInstanceObject(Object targetobObject){
		this.targetObject = targetobObject;

		return Proxy.newProxyInstance(targetobObject.getClass().getClassLoader(), 
						targetobObject.getClass().getInterfaces(),
						this);
		
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		checkSecurity();
		
		//调用目标方法
		Object ret = method.invoke(targetObject, args);
		
		return ret;
	}
	
	private void checkSecurity(){
		System.out.println("-----------checkSecurity----------");
	}

}

     这样,我们就可以直接在客户端进行调用执行了:

Client.java:

package com.ysc.spring;

/**
 * 
 * 动态代理可以将系统中一些独立的服务(这些独立的服务具有横切性)
 * 而将这些独立的服务拿出来,使用动态代理就可以在运行时将服务自动加入到里头;
 * @author root
 *
 */
public class Client {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SecurityHandler handler = new SecurityHandler();
		
		UserManager userManager = (UserManager)handler.createProxyInstanceObject(new UserManagerImpl());
		
		userManager.addUser("zhangsan", "123");
	}

}

          通过上面的例子可以看出,通过动态代理我们实现了动态的将检查安全性切入到每一个方法中,但是动态代理依靠接口实现,那么这样的话就会导致一些没有接口的类,就不能通过jdk实现java的动态代理,而这个时候我们就需要转向cglib的动态代理:

♚  cglib动态代理

       cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个类,并覆盖其中方法实现增强,看上述例子的cglib动态代理的实现:

       与动态代理不同,由于是针对类来实现,所以上述UserManagerImpl类不能直接在java代码中实现UserManager接口,所以我们需要一个配置文件来配置,且完成对哪些方法添加检查安全性的方法,ApplicationContext.xml 如下:




	
	
	
	 
	
	
	
	
	
		
			
			
		
	

       动态代理中例子保持Client.java , Security.java , UserManager.java不变,只对UserManagerImpl.java 做出如下的修改:

package com.ysc.spring;

public class UserManagerImpl  {
//implements UserManager {

	
	public void addUser(String username, String password) {
		//checkSecurity();
		System.out.println("-------------userManager.add()---------");
	}

	public void delUser(int userId) {
		//checkSecurity();
		System.out.println("-------------userManager.delUser()---------");
	}
		
	public String findUserById(int userId) {
		//checkSecurity();
		System.out.println("-------------userManager.findUserById()---------");
		return "张三";
	}

	public void modifyUser(int userId, String username, String passwordString) {
		//checkSecurity();
		System.out.println("-------------userManager.modifyUser()---------");
	}

}

 ✎   总结

 spring 默认使用的jdk的动态代理;

1.如果目标对象实现了接口,在默认情况下采用jdk的动态代理实现aop

2.如果目标对象实现了接口,也可以强制使用cglib生成代理实现aop

3.如果目标对象没有实现接口,那么必须引入cglib,spring会在jdk的动态代理和cglib代理之间切换

如何使用cglib强制生成代理;

* 加入cglib类库,cglib/*.jar

* 加入如下配置,表示强制使用cglib代理

jdk动态代理和cglib代理的区别:

* jdk动态代理对实现了接口的类进行代理

* cglib代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以我们的目标最好不要使用使用final声明;

      到这里,jdk动态代理和cglib的动态代理之间的对比就已经结束了,希望能帮大家更深刻的理解静态代理、jdk动态代理和cglib动态代理。如果有更好的理解和建议,请留言哦!!

       细说java动态代理和cglib的动态代理_第1张图片


你可能感兴趣的:(----,Java基础,♣【Java菜鸟成长日记】)