代理模式

定义: 给某对象提供一个代理对象,通过代理对象可以访问该对象的功能。主要解决通过代理去访问[不能直接访问的对象,例如 租房中介,你可以直接通过中介去了解房东的房源信息,此时中介就可以称为代理。

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

代理实现方式:
基于接口的动态代理

  • 提供者:JDK官方的Proxy类。
  • 要求:被代理类最少实现一个接口。
    基于子类的动态代理
  • 提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。
  • 要求:被代理类不能用final修饰的类(最终类)。

JDK动态代理

JDK动态代理要点:

  1. 被代理的类必须实现一个接口
  2. 创建代理对象的时候,用JDK代理需要实现InvocationHandler
  3. 代理过程在invoke中实现

我们以王五租房为例,王五通过中介直接租用户主房屋,中介在这里充当代理角色,户主充当被代理角色。
创建房东接口对象: LandlordService

public interface LandlordService { 
	void rentingPay(String name); 
}

创建房东对象: Landlord

public class Landlord implements LandlordService{ 
	/**** 
	* @param name 
	*/ 
	@Override 
	public void rentingPay(String name){ System.out.println(name+" 来交租!"); 
	} 
}

创建代理处理过程对象: QFangProxy

public class QFangProxy implements InvocationHandler{ 
	private Object instance; 
	public QFangProxy(Object instance) { 
		this.instance = instance; 
	} 
	/**** 
	* 代理过程 
	* @throws Throwable 
	*/ 
	@Override 
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
		args[0] = "中介QFang带领租户"+args[0]; 
		Object result = method.invoke(instance, args); 
		return result; 
	} 
}

创建代理,并通过代理调用房东方法: JdkProxyTest

public class JdkProxyTest { 
	public static void main(String[] args) { 
	    //给QFang产生代理 
		LandlordService landlordService = new Landlord(); 
		QFangProxy proxy = new QFangProxy(landlordService); 
		LandlordService landlordServiceProxy = (LandlordService)Proxy.newProxyInstance(LandlordService.class.getClassLoader(), new Class[] {LandlordService.class}, proxy); 
		//通过代理对象调用Landlord对象的方法 
		landlordServiceProxy.rentingPay("王五"); 
	} 
} 

运行结果如下:

中介QFang带领客户  王五  来交租!

CGLib动态代理

CGLib动态代理要点:

  1. 代理过程可以实现MethodInterceptor(Callback)接口中的invoke来实现
  2. 通过Enhancer来创建代理对象

在上面的案例基础上,把 QFangProxy 换成 SFangProxy ,代码如下:

public class SFangProxy implements MethodInterceptor { 
	private Object instance; 
	public SFangProxy(Object instance) { 
		this.instance = instance; 
	} 
	/*** 
	* 代理过程 
	* @throws Throwable 
	*/ 
	@Override 
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 
		args[0]="S房网带租户"+args[0]; 
		return method.invoke(instance,args); 
	} 
} 

创建测试类: CGLibProxyTest,代码如下:

public class CGLibProxyTest { 
	public static void main(String[] args) { 
		//给QFang产生代理 
		LandlordService landlordService = new Landlord(); 
		SFangProxy proxy = new SFangProxy(landlordService); 
		LandlordService landlordServiceProxy = (LandlordService)Enhancer.create(LandlordService.class,proxy); 
		//通过代理对象调用Landlord对象的方法 
		landlordServiceProxy.rentingPay("王五"); 
	} 
} 

Spring AOP-动态代理

基于SpringAOP可以实现非常强大的功能,例如声明式事务、基于AOP的日志管理、基于AOP的权限管理等功能,利用AOP可以将重复的代码抽取,重复利用,节省开发时间,提升开发效率。Spring的AOP其实底层就是基于动态代理而来,并且支持JDK动态代理和CGLib动态代理,动态代理的集中体现在 DefaultAopProxyFactory类中,我们来解析下 DefaultAopProxyFactory类。

如果我们在spring的配置文件中不配置 <aop:config proxy-target-class=“true”>,此时默认使用的将是JDK动态 代理,如果配置了,则会使用CGLib动态代理。
JDK动态代理的创建 JdkDynamicAopProxy如下:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { 
	//创建代理对象 
	@Override 
	public Object getProxy(@Nullable ClassLoader classLoader) { 
		if (logger.isDebugEnabled()) { 
		logger.debug("Creating JDK dynamic proxy: target source is " + 
		this.advised.getTargetSource()); 
	} 
		Class<?>[] proxiedInterfaces = 
		AopProxyUtils.completeProxiedInterfaces(this.advised, true); 
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); 
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 
	} 
	@Override 
	@Nullable 
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
		//JDK动态代理过程 
	} 
}

CGLib动态代理的创建 ObjenesisCglibAopProxy如下:

protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
        Class<?> proxyClass = enhancer.createClass();
        Object proxyInstance = null;
        if (objenesis.isWorthTrying()) {
            try {
                proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
            } catch (Throwable var7) {
                logger.debug("Unable to instantiate proxy using Objenesis, falling back to regular proxy construction", var7);
            }
        }

        if (proxyInstance == null) {
            try {
                Constructor<?> ctor = this.constructorArgs != null ? proxyClass.getDeclaredConstructor(this.constructorArgTypes) : proxyClass.getDeclaredConstructor();
                ReflectionUtils.makeAccessible(ctor);
                proxyInstance = this.constructorArgs != null ? ctor.newInstance(this.constructorArgs) : ctor.newInstance();
            } catch (Throwable var6) {
                throw new AopConfigException("Unable to instantiate proxy using Objenesis, and regular proxy instantiation via default constructor fails as well", var6);
            }
        }

        ((Factory)proxyInstance).setCallbacks(callbacks);
        return proxyInstance;
}

工厂设计模式

定义: 工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种 创建对象的最佳方式。它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的 产品对象。

优点:

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。
  2. 屏蔽产品的具体实现,调用者只关心产品的接口。
  3. 降低了耦合度

工厂模式案例


我们来做这么一个案例,创建一个接口Product和Product的实现类Mobile以及Car,再定义一个具体的工厂对ProcutFactory,并通过ProductFactory来获取指定的Product。

Product接口:

public interface Product { 
	void show(); 
}

创建接口实现类Mobile:

public class Mobile implements Product { 
	@Override 
	public void show() { 
		System.out.println("HUWEI Mate 30 Pro"); } 
	} 

创建接口实现类Car:

public class Car implements Product { 
	@Override 
	public void show() { 
		System.out.println("国产车    BYD"); 
	} 
} 

创建工厂ProductFactory,根据参数创建指定产品对象:

public class ProductFactory { 
	/*** 
	* 调用info方法,传入需要创建的对象的名字来创建具体对象 * @param name 
	* @return 
	*/ 
	public Product info(String name){ 
		if(name.equals("mobile")){ 
			return new Mobile(); 
		}else if(name.equals("car")){ 
			return new Car(); 
		}else{ 
			return null; 
		} 
	} 
}

使用工厂ProductFactory创建指定对象:

public class ProductFactoryTest { 
	public static void main(String[] args) { 
	//创建ProductFactory 
	ProductFactory factory = new ProductFactory(); 
	//获取Mobile对象 
	Product mobile = factory.info("mobile"); 	
	mobile.show(); 
	//获取Car 
	Product car = factory.info("car"); 
	car.show(); 
	} 
}

运行结果如下:

HUWEI Mate 30 Pro 
国产车    BYD 

BeanFactory工厂模式

Spring内部源码也有工厂模式的实现,并且解决了上面我们提到的工厂模式的缺陷问题。
Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,但是否是在传入参 数后创建还是传入参数前创建这个要根据具体情况来定。

BeanFactory源码:

public interface BeanFactory { 
	//根据参数获取指定对象的实例 
	Object getBean(String name) throws BeansException; 
	<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException; Object getBean(String name, Object... args) throws BeansException; 
	<T> T getBean(Class<T> requiredType) throws BeansException; 
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException; 
}

在BeanFactory接口中,有多个getBean方法,该方法其实就是典型的工厂设计模式特征,在接口中定义了创建对象 的方法,而对象如何创建其实在接口的实现类中实现 DefaultListableBeanFactory。

我们用Spring的工厂对象BeanFactory来解决上面工厂模式案例所带来的问题。

案例:

<bean id="car" class="com.factory.Car"/> 
<bean id="mobile" class="com.factory.Mobile"/> 

测试:

public void testBeanFactory(){ 
	//加载核心配置文件         beas.xml 
	Resource resource = new ClassPathResource("beans.xml"); 
	//创建容器对象BeanFactory 
	BeanFactory beanFactory = new XmlBeanFactory(resource); 
	//使用Car对象 
	Product car = (Product) beanFactory.getBean("car"); 
	//使用Mobile对象 
	Product mobile = (Product) beanFactory.getBean("mobile"); 
	car.show(); 
	mobile.show(); 
} 

结果:

国产车    BYD 
HUWEI Mate 30 Pro 

使用Spring的BeanFactory,以后要新增一个产品,只需要创建产品对应的xml配置即可,而不需要像 ProductFactory那样硬编码存在。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐