spring aop的实现代码

2 篇文章 0 订阅

跟踪spring aop的实现

aop核心概念介绍

  • 什么是切面编程
    在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面编程。

  • Aspect(切面)
    什么是切面呢?切面这个词感觉还是挺抽象的,咱们可能知道点构成线,线构成面的数据话术。但是在编程语言中如何体现这个面呢?我的理解是“在程序中切面是由切入点和在切入点的表现的行为构成”。给个在spring中定义切面的例子如下:

<bean id="advice" class="com.im.sky.spring.aspect.GenericAdvice" />
	
    <aop:config>
        <aop:aspect id="aspect1" ref="advice">
            <aop:pointcut id="p1" expression="execution(* com.im.sky.spring.bean.People.say(..))" />
            <aop:before pointcut-ref="p1" method="before" />
        </aop:aspect>

其中aop:aspect表示的就是一个切面,而aop:pointcut表示的是具体的切入点,即哪些类的哪些放到会被这个切面切到。aop:before表示的就是在切入点的哪一个位置执行什么行为。

  • crosscutting concerns(横切关注点)
    在实现业务的同时,可能会在代码逻辑中加入日志、参数校验、安全检查,这些通用的操作在aop中就叫做横切关注点,因为这类代码是可以通用的,可以进行抽离,通过借助于aop,可能将此类代码和传统的业务代码就行解耦。

  • Advice
    在切入点的具体实现,就称之为Advice,正如spring中定义的aop:before、aop:after处进行的行为等。

  • JoinPoint
    Advice在业务代码执行时加入业务流程的点或者时机称之为JoinPoint,目前Spring只支持方法级别,但可以在方法的不同时机加入,比如调用方法之前、之后、返回之后、返回失败时。

  • Pointcut(切入点)
    Pointcut可以看做是JoinPoint的一个子集,对于每一个方法都会有一些切入的时机,但是呢,你可能只想切入你关注的一些方法,这些方法称之为切入点。

Spring中的aop

aop的实现原理还是借助于动态代理实现的,而目前就是使用JDK动态代理和Cglib动态代理,当一个类实现接口时才可以使用JDK动态代理,而Cglib不受此限制。

步骤一:定义spring aop配置

<bean id="advice" class="com.im.sky.spring.aspect.GenericAdvice" />

    <aop:config>
        <aop:aspect id="aspect1" ref="advice">
            <aop:pointcut id="p1" expression="execution(* com.im.sky.spring.bean.People.say(..))" />
            <aop:before pointcut-ref="p1" method="before" />
        </aop:aspect>

步骤二:定义基本类

People类

public class People {

    private String name;

    public void setName(String name) {
        System.out.println("name:" + name);
        this.name = name;
    }

    public void say() {
        System.out.println("说人话");
    }

    public void cry() {
        System.out.println("痛苦才会哭");
    }
}

advice类

public class GenericAdvice {

    public void before() {
        System.out.println("before advice");
    }

    public void after() {
        System.out.println("after advice");
    }

    public void iReturn() {
        System.out.println("return advice");
    }

    public void throwsError() {
        System.out.println("throws advice");
    }

    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around advice for before");
        Object o = pjp.proceed(pjp.getArgs());
        System.out.println("around advice for after");
        return o;
    }
}

执行类Main

public class Main {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        People people = context.getBean(People.class);
        people.say();
    }
}

spring中核心类:AbstractAutoProxyCreator

protected Object createProxy(
			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}
		
		// 构建一个代理类工厂
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		// 设置目标类,就是上面定义的People的实例(在spring配置文件中定义了一个,没有粘贴)
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
		//这里是核心,内部会选择是采用JDK动态代理还是CgLib动态代理
		return proxyFactory.getProxy(getProxyClassLoader());
	}

proxyFactory.getProxy(ClassLoader loader)源码

public Object getProxy(ClassLoader classLoader) {
		// 下面看看如何构建aop代理对象的
		return createAopProxy().getProxy(classLoader);
	}
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.");
			}
			// 如果目标类是接口或者本身就是一个代理类才会采用JDK动态代理
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			// 这里内部用的就是Cglib动态代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

当选择具体采用哪种代理方式后,就会调用getProxy构成具体的目标类的代理类对象。
JDK动态代理构建目标类代理对象源码:

public Object getProxy(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);
	}

Cglib动态代理构建目标类代理对象源码:

public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
		}

		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			if (ClassUtils.isCglibProxyClass(rootClass)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		enhancer.setInterceptDuringConstruction(false);
		enhancer.setCallbacks(callbacks);
		return (this.constructorArgs != null ?
				enhancer.create(this.constructorArgTypes, this.constructorArgs) :
				enhancer.create());
	}

怎么说呢,spring中的代码还是很庞大的,如果想仔细的了解,就debug进入跟踪一下吧,我这个写的也是很少的一部分,中间还涉及预处理等很多东西。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值