Spring Aop(十一)——编程式的创建Aop代理之ProxyFactory

简介: 编程式的创建Aop代理之ProxyFactory Spring Aop是基于代理的,ProxyFactory是Spring Aop内部用来创建Proxy对象的一个工厂类。如果我们需要在程序运行时来动态的应用Spring Aop,则我们可以考虑使用ProxyFactory。

编程式的创建Aop代理之ProxyFactory

Spring Aop是基于代理的,ProxyFactory是Spring Aop内部用来创建Proxy对象的一个工厂类。如果我们需要在程序运行时来动态的应用Spring Aop,则我们可以考虑使用ProxyFactory。使用ProxyFactory时,我们需要为它指定我们需要代理的目标对象、代理时我们需要使用的Advisor或Advice。如下示例就是一个简单的使用ProxyFactory创建MyService对象的代理,同时对其应用了一个MethodBeforeAdvice,即每次调用代理对象的方法时都将先调用MethodBeforeAdvice的before方法。

	@Test
	public void testProxyFactory() {
		MyService myService = new MyService();
		ProxyFactory proxyFactory = new ProxyFactory(myService);
		proxyFactory.addAdvice(new MethodBeforeAdvice() {

			@Override
			public void before(Method method, Object[] args,
                            Object target) throws Throwable {
				System.out.println("执行目标方法调用之前的逻辑");
				//不需要手动去调用目标方法,
                                //Spring内置逻辑里面会调用目标方法
			}
			
		});;
		MyService proxy = (MyService) proxyFactory.getProxy();
		proxy.add();
	}

指定被代理对象

ProxyFactory有多个重载的构造函数,上面示例中笔者用的是指定被代理对象的构造函数,如果我们应用的是其它构造函数,则可以通过ProxyFactory的setTarget(Object)方法来指定被代理对象。如果我们没有指定被代理对象的Class,那么默认创建出来的代理对象是我们传递的被代理对象的类型,即获取的是targetObject.getClass()类型。如果我们的被代理对象的类型是包含多个接口实现或父类型的,而我们只希望代理其中的某一个类型时,我们可以通过ProxyFactory的setTargetClass(Class)来指定创建的代理对象是基于哪个Class的。默认情况下,ProxyFactory会根据实际情况选择创建的代理对象是基于JDK代理的还是基于CBLIB代理的,即目标对象拥有接口实现且没有设置proxyTargetClass="true"或者指定的targetClass是一个接口的时候将采用JDK代理,否则将采用CGLIB代理。也就是说即算是你通过ProxyFactory.setProxyTargetClass(true)指定了将会建立基于Class的CGLIB代理,最终也不一定是CGLIB代理,因为这种情况下如果targetClass是一个接口也将建立JDK代理。这块的逻辑是由DefaultAopProxyFactory的createAopProxy()方法实现的,其源码如下。

	public AopProxy createAopProxy(AdvisedSupport config) 
            throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass()
                     || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				

throw new AopConfigException("TargetSource cannot determine target class: " +
	"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface()) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

ProxyFactory底层在创建代理对象的时候实际上是会委托给AopProxyFactory对象的,AopProxyFactory是一个接口,其只定义了一个createAopProxy()方法,Spring提供了一个默认实现,DefaultAopProxyFactory。ProxyFactory中使用的就是DefaultAopProxyFactory,有兴趣的朋友可以参考一下ProxyFactory的源代码。

指定Advisor

使用Aop时我们是需要对拦截的方法做一些处理的,对于Spring Aop来讲,需要对哪些方法调用做什么样的处理是通过Advisor来定义的,通常是一个PointcutAdvisor。PointcutAdvisor接口中包含主要有两个接口方法,一个用来获取Pointcut,一个用来获取Advice对象,它俩的组合就构成了需要在哪个Pointcut应用哪个Advice。所以有需要的时候我们也可以实现自己的Advisor实现。

/**
 * 简单的实现自己的PointcutAdvisor
 * @author Elim 2017年5月9日
 */
public class MyAdvisor implements PointcutAdvisor {

	@Override
	public Advice getAdvice() {
		return new MethodBeforeAdvice() {

			@Override
			public void before(Method method, Object[] args, 
  
                            Object target) throws Throwable {
				

System.out.println("BeforeAdvice实现,在目标方法被调用前调用,目标方法是:" 

+ method.getDeclaringClass().getName() + "."
						+ method.getName());
			}
		};
	}

	@Override
	public boolean isPerInstance() {
		return true;
	}

	@Override
	public Pointcut getPointcut() {
		//匹配所有的方法调用
		return Pointcut.TRUE;
	}

}
	@Test
	public void testProxyFactory2() {
		MyService myService = new MyService();
		ProxyFactory proxyFactory = new ProxyFactory(myService);
		proxyFactory.addAdvisor(new MyAdvisor());
		MyService proxy = (MyService) proxyFactory.getProxy();
		proxy.add();
	}

上述示例就是一个指定代理对象对应的Advisor的示例。其实一个代理对象可以同时绑定多个Advisor对象,ProxyFactory的addAdvisor()方法可多次被调用,且该方法还有一些重载的方法定义,可以参数Spring的API文档。

指定Advice

我们的第一个示例指定的代理对象绑定的是一个Advice,而第二个示例指定的Advisor,对此你会不会有什么疑问呢?依据我们对Spring Aop的了解,Spring的Aop代理对象绑定的就一定是一个Advisor,而且通常是一个PointcutAdvisor,通过它我们可以知道我们的Advice究竟是要应用到哪个Pointcut(哪个方法调用)?当我们通过ProxyFactory在创建代理对象时绑定的是一个Advice对象时,实际上ProxyFactory内部还是为我们转换为了一个Advisor对象的,只是该Advisor对象对应的Pointcut是一个匹配所有方法调用的Pointcut实例。

指定是否需要发布代理对象

在调用Aop代理对象的方法时,默认情况下我们是不能访问到当前的代理对象的,如果我们指定了创建的代理对象需要对外发布代理对象,那么在调用代理对象的方法时Spring会把当前的代理对象存入AopContext中,我们就可以在目标对象的方法中通过AopContext中获取到当前的代理对象了。这是通过exposeProxy属性来指定的,如果我们希望对外发布代理对象,我们可以通过exposeProxy的set方法来指定该属性的值为true。如:

	@Test
	public void testProxyFactory2() {
		MyService myService = new MyService();
		ProxyFactory proxyFactory = new ProxyFactory(myService);
		proxyFactory.setExposeProxy(true);//指定对外发布代理对象,即在目标对象方法中可以通过AopContext.currentProxy()访问当前代理对象。
		proxyFactory.addAdvisor(new MyAdvisor());
		proxyFactory.addAdvisor(new MyAdvisor());//多次指定Advisor将同时应用多个Advisor
		MyService proxy = (MyService) proxyFactory.getProxy();
		proxy.add();
	}

除了上述配置信息以外,ProxyFactory其实还可以配置很多其它的信息,更多的配置信息项请参考ProxyFactory的源代码或参考Spring API文档。

参考文档

  • Spring4.1.0官方文档
  • Spring源代码

(本文是基于Spring4.1.0所写,Elim写于2017年5月9日)

目录
相关文章
|
20天前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
43 1
|
12天前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
2天前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
25 9
|
14天前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)
|
25天前
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
5月前
|
安全 Java Spring
Spring之Aop的底层原理
Spring之Aop的底层原理
|
5月前
|
设计模式 Java uml
Spring AOP 原理
Spring AOP 原理
32 0
|
5月前
|
监控 Java Spring
Spring AOP的作用和底层原理、AOP相关术语
Spring AOP的作用和底层原理、AOP相关术语
78 0
|
12月前
|
Java Spring 容器
【Spring AOP底层实现原理】
【Spring AOP底层实现原理】
133 0
|
2月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现