代理模式静态代理 动态代理(JDK代理、cglib代理)

版权声明:Arno https://blog.csdn.net/yu342107056/article/details/85793851

面向对象的设计原则:

开闭原则:对于修改来说是关闭,对于扩展来说是开放的
单一职责原则:
       一个项目的功能单一
       一个模块的功能单一
       一个接口/类的功能单一
       一个方法的功能单一
       一个变量的功能单一

代理设计模式:

提出一个问题:

  有一套原有的业务模型   符合单一职责
  有一套新的功能                 符合单一职责
  要把新的功能添加到原有业务模型中,填在原有业务模型的前或后,不是添在中间

解决方案:

方案一:
        在原有业务方法的第一行填写新功能代码
        在原有业务方法的最后一行填写新功能代码
        违反开闭原则,和单一职责
        是能完成添加新功能的需求,只是设计的不太好
方案二:
        代理设计模式实现
         遵守开闭原则,和单一职责

代理设计模式的分类:

静态代理
动态代理
        jdk的动态代理
        cglib的动态代理

静态代理:

原有的业务模型
 UserDao.java        UserDaoImpl.java
 UserService.java     UserServiceImpl.java
新功能:事务管理
  TransactionManager.java
目标:要把新的功能(事务管理)切入到指定业务方法的前或后
      在业务方法的前添加事务的开启
      在业务方法的后添加事务的,没错误就提交,有错误就回滚

 原有业务有了
 新业务也有了
 新建一个类,在新建类中把老业务和新业务耦合在一起

TransactionManager.java

	/**
	 * 此类是一个新功能类,用于给原有业务添加事务处理的功能
	 * 符合单一职责原则,此类只做事务管理
	 * @author Administrator
	 *
	 */
	public class TransactionManager {
		/**
		 * 事务的开启
		 */
		public void begin(){
			System.out.println("事务开启");
		}
		/**
		 * 事务提交
		 */
		public void commit(){
			System.out.println("事务提交");
		}
		/**
		 * 事务的回滚
		 */
		public void rollback(){
			System.out.println("事务回滚");
		}
	}


StaticProxy.java
    
	public class StaticProxy implements UserService {
		//老业务
		private UserService userService;
		
		//新业务
		private TransactionManager transactionManager;
		
		public void setUserService(UserService userService) {
			this.userService = userService;
		}
	
		public void setTransactionManager(TransactionManager transactionManager) {
			this.transactionManager = transactionManager;
		}
	
		@Override
		public boolean addUser(User user) {
			try{
				transactionManager.begin();
				userService.addUser(user);
				transactionManager.commit();
			}catch(Exception e){
				transactionManager.rollback();
				e.printStackTrace();
			}
			return false;
		}
	
		@Override
		public boolean updateUser(User user) {
			try{
				transactionManager.begin();
				userService.updateUser(user);
				transactionManager.commit();
			}catch(Exception e){
				transactionManager.rollback();
				e.printStackTrace();
			}
			return false;
		}
		
	
	}

总结静态代理:

1.原有的老业务,没有被破坏,符合单一职责
2.新的业务,符合单一职责
3.把新的业务要添加到老业务中
a.新建一个老业务和新业务的耦合类,此耦合类就叫做静态代理类
b.静态代理类要求必须实现自业务的接口,因为静态代理类的功能不能少于原有业务功能
c.静态代理类不满足单一职责原则,因为老功能和新功能耦合在一起
d.每一个套业务,都会对应一个静态代理类
比如:UserService UserStaticProxy implements UserService
ProductService ProductStaticProxy implements ProductService
业务的模型越多,静态代理类就越多
程序员会额外写很多的静态代理类,增加程序员的负担
e.每个静态代理类都会创建很多代理对象
f.静态代理是在编译期间就确定了老业务和新业务的耦合关系

动态代理:(jdk动态代理,cglib动态代理)

jdk动态代理:是由jdk提供的功能
老的业务功能:
  UserDao.java    UserDaoImpl.java
  UserService.java    UserServiceImpl.java
新的业务功能:
  TransactionMananger.java
目的:把新的功能添加到老业务功能,遵守开闭原则和单一职责原则
学习jdk动态代理的几个层次
1.能够写出jdk动态代理的代码
2.能清晰的了解jdk动态代理的调用关系  参见:jdk动态代理调用原理图.png
3.了解jdk的动态代理类的内容
jdk的动态代理流程
1.创建生成代理对象的类JDKProxy.java       getProxyObject方法用户生成代理对象
2.创建InvocationHandler接口的子实现,在子实现中的invoke方法把老业务功能和新业务功能耦合
OldAndNewtogether.java      invoke方法,耦合了新和老的业务

在jdk创建代理对象的之前,由jdk底层根据目标对象和目标对象所对应的接口,
创建出代理类,此代理类只是临时出现,用完就没有了,
创建完代理类,实例化此代理类的对象,Object proxyObject=Proxy.newProxyInstance(参数一,参数二,参数三);
只有调用Object proxyObject=Proxy.newProxyInstance(参数一,参数二,参数三);才会生成代理类和代理对象
下面是生成的代理类的模型:

/**
 * jdk的代理类,由jdk的底层创建的
 * @author Administrator
 *
 */
public final class $Proxy0 extends Proxy implements UserService {
	//静态代码块,m0---mx赋值  类型是Method
	static {
		try {
			m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
			m1 = Class.forName("java.lang.Object").getMethod("equals",
					new Class[] { Class.forName("java.lang.Object") });
			m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
			m3 = Class.forName("com.arno.service.UserService").getMethod("addUser",
					new Class[] { Class.forName("com.tarean.entity.User") });
			m4 = Class.forName("com.arno.service.UserService").getMethod("updateUser",
					new Class[] { Class.forName("com.tarean.entity.User") });
			
			return;
		} catch (NoSuchMethodException localNoSuchMethodException) {
			throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
		} catch (ClassNotFoundException localClassNotFoundException) {
			throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
		}
	}
	//若干私有属性
	private static Method m0;//hashCode方法,从Object中获取
	private static Method m1;//equals方法,从Object中获取
	private static Method m2;//toString方法,从Object中获取
	private static Method m3;//addUser方法,从UserService接口中获取
	private static Method m4;//updateUser方法,从UserService接口中获取
	
    //代理类构造
	public $Proxy0(InvocationHandler paramInvocationHandler)throws {
		super(paramInvocationHandler);
	}
    
	//重写UserService接口的addUser方法
    public final void addUser(User user)throws{
    	try{
    		this.h.invoke(this, m3, new Object[] { user });
    		return;
    	}catch (Error|RuntimeException localError){
    		throw localError;
    	}catch (Throwable localThrowable){
    		throw new UndeclaredThrowableException(localThrowable);
    	}
    }
    //重写UserService接口的updateUser方法
    public final void updateUser(User user)throws{
    	try{
    		this.h.invoke(this, m4, new Object[] { user });
    		return;
    	}catch (Error|RuntimeException localError){
    		throw localError;
    	}catch (Throwable localThrowable){
    		throw new UndeclaredThrowableException(localThrowable);
    	}
    }
    
    //equals方法
    public final boolean equals(Object paramObject)throws {
    	try{
    		return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    	}catch (Error|RuntimeException localError){
    		throw localError;
    	}catch (Throwable localThrowable){
    		throw new UndeclaredThrowableException(localThrowable);
    	}
    }
    public final String toString()throws{
    	try{
    		return (String)this.h.invoke(this, m2, null);
    	}catch (Error|RuntimeException localError){
    		throw localError;
    	}catch (Throwable localThrowable){
    		throw new UndeclaredThrowableException(localThrowable);
    	}
    }

    public final int hashCode()throws{
    	try{
    		return ((Integer)this.h.invoke(this, m0, null)).intValue();
    	}catch (Error|RuntimeException localError){
    		throw localError;
    	}catch (Throwable localThrowable){
    		throw new UndeclaredThrowableException(localThrowable);
    	}
    }	
}
总结jdk动态代理:
1.原有的老业务,没有被破坏,符合单一职责 UserService.java
2.新的业务,符合单一职责 TransactionManager.java
3.创建一个java类用户生成代理对象JDKProxy.java    
4.把新的业务要添加到老业务中
    a.必须实现InvocationHandler接口   OldAndNewTogether.java
    b.重写invoke的方法
    c.在方法中把老业务和新业务耦合
5.一定要先由jdk生成代理类    参见:$Proxy0.java
6.由代理类生成代理对象
7.代理对象和目标对象是兄弟关系
   代理类和目标类是兄弟关系
8.jdk动态代理要求目标类必须接口 
9.jdk的代理类是在运行期间出现,一定不在编译期间出现
   所谓的动态代理是代理类是动态出现的,什么时候调用,什么时候出现代理类

CGLIB动态代理:需要第三方库支撑

总结CGLIB动态代理:
0.需要额外第三方jar支撑
1.原有的老业务,没有被破坏,符合单一职责 UserService.java
2.新的业务,符合单一职责 TransactionManager.java
3.创建一个java类用户生成代理对象CGLIBProxy.java    
4.把新的业务要添加到老业务中
    a.必须实现MethodInterceptor接口   OldAndNewTogether.java
    b.重写intercept的方法
    c.在方法中把老业务和新业务耦合
5.一定要先由asm.jar生成代理类    
6.由代理类生成代理对象
7.代理对象和目标对象是父子关系     
  目标类是代理类的父亲
   目标类不能是final
8.cglib动态代理的目标类有无接口皆可 
9.cglib的代理类是在运行期间出现,一定不在编译期间出现
   所谓的动态代理是代理类是动态出现的,什么时候调用,什么时候出现代理类

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

jdk动态代理:
1.目标类必须有接口
2.代理对象和目标对象是兄弟关系
3.代理类是在运行期间动态创建的
4.创建代理对象快,用代理对象执行目标方法的时候是慢
5.jdk动态代理会把代理类缓存
cglib动态代理:
1.目标类有无接口皆可,但不能是final类
2.目标类是代理类的父类
3.代理类是在运行期间动态创建的
4.创建代理对象慢,用代理对象执行目标方法的时候快

代理就把新功能横切到原有业务上,在满足开闭原则和单一职责前提下
可以把新功能看成某一方面的功能,把某一个方面的功能横切到需要的业务上
spring aop的底层原理就是用的动态代理(有接口就用jdk,没有接口就用cglib)

提出问题:
jdk动态代理和cglib动态代理,把新功能横切到原有老业务中的所有方法上
能否把新功能横切到业务中的指定的一部分方法上,其他的业务方法不需要横切

答案:用spring aop可以对部分业务方法横切

猜你喜欢

转载自blog.csdn.net/yu342107056/article/details/85793851