profile是Spring3.1提供的一个新的配置项,在下面的测试示例中,又有使用了多种AOP配置方式,为了将各种配置方式进行对比在此使用了profile.在测试用例中通过使用@ActiveProfiles("four")注解指定profile的值。
Aop 是Spring 框架的核心功能之一。
Advice 通知时定义在该连接点做什么,为切面增强提供织入接口。Advice是AOP联盟定义的一个接口,在Spring中对其进行了扩展,提供了更为具体的接口如:BeforeAdvice,AfterAdvice,ThrwosAdvice等。
Pointcut切点,决定advice通知应该作用于哪个连接点,也就是说Pointcut来定义需要增强方法的集合,这些集合的选取可以按照一定的规则来完成。Spring中默认提供了JdkRegexpMethodPointcut,基于正则表达式去匹配增强方法。
Advisor通知器,在完成对既定目标的增强切面的设计(advice)和关注点的设计(Pointcut)以后,还需要将Advice和Pointcut两者关联起来,完成这个工作的就是Advisor. 通过Advisor,可以定义在哪个关注点上使用哪个通知。在Spring 中默认提供了一个DefultPointcutAdvisor,并以此为例完成AOP demo.
在Spring AOP 使用中可以通过ProxyFactoryBean来配置目标对象和切面的行为。在ProxyFactoryBean中通过interceptorNames属性来配置已经定义好的advisor.虽然名字是interceptor实际上就是配置advisor.在ProxyFactoryBean中需要为target目标对象生成一个动态代理对象proxy,从而为AOP切面的编织做好准备工作。
ProxyFactoryBean对象中创建一个代理对象的过程是:
- addGlobalAdvisor
- getSingletonInstance
/** * 返回一个代理对象。当客户端从这个FactoryBean中获取bean时调用该接口 */ public Object getObject() throws BeansException { //初始化通知器链 initializeAdvisorChain(); //如果是单例的则返回一个单例实例 if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } //返回以prototype实例 return newPrototypeInstance(); } } /** * 返回一个单例的代理对象 */ private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { this.targetSource = freshTargetSource(); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // 根据AOP框架来判断需要代理的接口 Class targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } //设置代理接口 setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // 初始化一个单例 super.setFrozen(this.freezeProxy); this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; } /** * 创建一个通知器链 */ private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException { //如果通知器链已经初始化则直接返回 if (this.advisorChainInitialized) { return; } // 如果没有配置过通知器则抛出异常 if (!ObjectUtils.isEmpty(this.interceptorNames)) { if (this.beanFactory == null) { throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " + "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames)); } //如果没有指定targetSource则最后一个通知器不能是全局通知器 if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) && this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) { throw new AopConfigException("Target required after globals"); } // 通过通知器名称获取通知器对象 for (String name : this.interceptorNames) { if (logger.isTraceEnabled()) { logger.trace("Configuring advisor or advice '" + name + "'"); } //如果通知器名称是以*结尾的且beanFactory不适ListableBeanFactory则抛出异常,否则添加全局通知器 if (name.endsWith(GLOBAL_SUFFIX)) { if (!(this.beanFactory instanceof ListableBeanFactory)) { throw new AopConfigException( "Can only use global advisors or interceptors with a ListableBeanFactory"); } addGlobalAdvisor((ListableBeanFactory) this.beanFactory, name.substring(0, name.length() - GLOBAL_SUFFIX.length())); } else { //非全局通知器 Object advice; //如果该beanFactory是单例的或者是通知器是单例的则从beanFactory中获取单例的通知器,否则获取一个原型的通知器 if (this.singleton || this.beanFactory.isSingleton(name)) { advice = this.beanFactory.getBean(name); } else { advice = new PrototypePlaceholderAdvisor(name); } //添加到通知器链中 addAdvisorOnChainCreation(advice, name); } } } //设置通知器初始化完成标识 this.advisorChainInitialized = true; } /** * 添加所有的通知器和切点 */ private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) { //获取beanFactory中定义的所有的通知器 String[] globalAdvisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Advisor.class); // 获取beanFactory中定义的所有的Interceptor String[] globalInterceptorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, Interceptor.class); List<Object> beans = new ArrayList<Object>(globalAdvisorNames.length + globalInterceptorNames.length); Map<Object, String> names = new HashMap<Object, String>(beans.size()); //遍历所有的通知器 for (String name : globalAdvisorNames) { Object bean = beanFactory.getBean(name); beans.add(bean); names.put(bean, name); } //遍历所有拦截器 for (String name : globalInterceptorNames) { Object bean = beanFactory.getBean(name); beans.add(bean); names.put(bean, name); } //排序 OrderComparator.sort(beans); //遍历所有,如果拦截器或通知器是以指定的前缀开始的则添加到通知器中 for (Object bean : beans) { String name = names.get(bean); if (name.startsWith(prefix)) { addAdvisorOnChainCreation(bean, name); } } } /** * 添加一个通知器 */ private void addAdvisorOnChainCreation(Object next, String name) { //转换为一个通知器 Advisor advisor = namedBeanToAdvisor(next); if (logger.isTraceEnabled()) { logger.trace("Adding advisor with name '" + name + "'"); } //添加通知器 addAdvisor(advisor); } }
在ProxyFactoryBean中 getSingletoneInstance中有调用一个createAopProxy(),该方法是定义在ProxyCreatorSupport类中
protected final synchronized AopProxy createAopProxy() { if (!this.active) { activate(); } return getAopProxyFactory().createAopProxy(this); }
DefaultAopProxyFactory,这里是实际创建代理的地方
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); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }
通过上述代码可以发现Spring AOP中,是通过CGLIB或者JDK 动态代理实现的。
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) { throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; }到此我们已经完成了一个代理对象创建。当我们创建一个代理对象后调用代理对象时则会触发InvocationHandler接口的invoke方法
/** * InvocationHandler接口的invoke实现方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; //获取TargetSource TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null; try { //如果目标对象没有实现equals方法 if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // The target does not implement the equals(Object) method itself. return equals(args[0]); } //如果目标对象没有实现hashCode if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); } Object retVal; if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // 获取目标对象 target = targetSource.getTarget(); //如果目标对象不是null,则初始化targetClass if (target != null) { targetClass = target.getClass(); } // 获取这个方法的拦截器链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); //如果拦截器链为空则表示这个方法配置配拦截器,则直接调用target对应的方法 if (chain.isEmpty()) { retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { //如果有配置拦截器,那么需要构建一个ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // 沿着拦截器链进行处理 retVal = invocation.proceed(); } if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
在上述的代码中有一个getInterceptorsAndDynamicInterceptionAdvice()获取拦截器链
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice( this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }
protected ReflectiveMethodInvocation( Object proxy, Object target, Method method, Object[] arguments, Class targetClass, List<Object> interceptorsAndDynamicMethodMatchers) { this.proxy = proxy; this.target = target; this.targetClass = targetClass; this.method = BridgeMethodResolver.findBridgedMethod(method); this.arguments = arguments; this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers; }
public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 从-1的索引位置开始先自增后执行拦截器,如果当前索引已经是最后一个则直接调用这个连接点 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { return invokeJoinpoint(); } //获取指定索引位置的拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); // 如果拦截器是InterceptorAndDynamicMethodMatcher if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; //如果拦截器匹配方法成功则实行该拦截器 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { // 如果匹配失败则跳过该拦截器,执行下一个拦截器 return proceed(); } } else { // 如果是一个拦截器则直接调用 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } }
到此我们已经可以对Spring AOP 有一个基本的认识!下面是一个DEMO的实现
/** * 方法调用前的权限拦截器 * @author zhangwei_david * @version $Id: AuthInterceptor.java, v 0.1 2015年7月10日 上午10:18:12 zhangwei_david Exp $ */ public class AuthInterceptor implements MethodBeforeAdvice { /** * @see org.springframework.aop.MethodBeforeAdvice#before(java.lang.reflect.Method, java.lang.Object[], java.lang.Object) */ public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("调用 方法:" + method); } }
/** * * @author zhangwei_david * @version $Id: AopDemo.java, v 0.1 2015年7月10日 上午10:21:20 zhangwei_david Exp $ */ public class AopDemo implements Say { public void say() { System.out.println("hello"); } }
/** * * * @author zhangwei_david * @version $Id: SpringAopTest.java, v 0.1 2015年7月10日 上午10:51:16 zhangwei_david Exp $ */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:META-INF/spring/aop-beans.xml") public class SpringAopTest { @Autowired private Say aopDemo; @Test public void test() { aopDemo.say(); } }
2015-07-10 10:40:14 [ main:375 ] - [ INFO ] Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@190a65e: defining beans [authInterceptor,authPoint,authAdvisor,aopDemo,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy 调用 方法:public abstract void com.cathy.demo.spring.aop.Say.say() hello 2015-07-10 10:40:14 [ Thread-0:494 ] - [ INFO ] Closing org.springframework.context.support.GenericApplicationContext@ee68d8: startup date [Fri Jul 10 10:40:14 CST 2015]; root of context hierarchy 2015-07-10 10:40:14 [ Thread-0:494 ] - [ INFO ] Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@190a65e: defining beans [authInterceptor,authPoint,authAdvisor,aopDemo,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
其他的配置方式如下:
/** * 方法调用前的权限拦截器 * @author zhangwei_david * @version $Id: AuthInterceptor.java, v 0.1 2015年7月10日 上午10:18:12 zhangwei_david Exp $ */ @Component @Aspect public class BeforeInterceptor { @Before("execution(* *.*(..))") public void before(JoinPoint joinPoint) throws Throwable { System.out.println("before [target" + joinPoint.getTarget() + ", signature:" + joinPoint.getSignature()); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd " default-autowire="byType"> <!-- 使用ProxyFactoryBean 实现aop --> <beans profile="one"> <!-- 定义一个通知 --> <bean id="authInterceptor" class="com.cathy.demo.spring.aop.AuthInterceptor" /> <!-- 定义切点,匹配所有方法 --> <bean id="authPoint" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <property name="pattern" value=".*" /> </bean> <!-- 定义通知 器 --> <bean id="authAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="pointcut" ref="authPoint" /> <property name="advice" ref="authInterceptor" /> </bean> <bean id="aopDemo" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target"> <bean class="com.cathy.demo.spring.aop.AopDemo" /> </property> <property name="interceptorNames" value="auth*" /> </bean> </beans> <!-- 优化配置,使用DefaultAdvisorAutoProxyCreator --> <beans profile="two"> <!-- 定义一个通知 --> <bean id="authInterceptor" class="com.cathy.demo.spring.aop.AuthInterceptor" /> <!-- 定义通知 器 --> <bean id="authAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="pattern" value=".*" /> <property name="advice" ref="authInterceptor" /> </bean> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" p:usePrefix="true" p:advisorBeanNamePrefix="auth" /> <bean id="aopDemo" class="com.cathy.demo.spring.aop.AopDemo" /> </beans> <!-- 使用aop命名空间进行配置 --> <beans profile="three"> <bean id="authInterceptor" class="com.cathy.demo.spring.aop.BeforeInterceptor" /> <bean id="aopDemo" class="com.cathy.demo.spring.aop.AopDemo" /> <aop:config> <aop:aspect ref="authInterceptor"> <aop:before method="before" pointcut="execution(* *.*(..))" /> </aop:aspect> </aop:config> </beans> <!-- 自动扫描 @Aspectj --> <beans profile="four"> <aop:aspectj-autoproxy /> <context:annotation-config /> <context:component-scan base-package="com.cathy.demo.spring.*" /> </beans> </beans>
/** * * * @author zhangwei_david * @version $Id: SpringAopTest.java, v 0.1 2015年7月10日 上午10:51:16 zhangwei_david Exp $ */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath*:META-INF/spring/aop-beans.xml") @ActiveProfiles("four") public class SpringAopFourTest { @Autowired private Say aopDemo; @Test public void test() { aopDemo.say(); } }
相关推荐
AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析-SpringAOP中定义的类图AOP流程源码分析...
SpringAop面向切面编程
SpringAop xml方式配置通知
Java流行框架源码分析:Spring源码、SpringBoot源码、SpringAOP源码、SpringSecurity源码、SpringSecurity OAuth2源码、JDK源码、Netty源码
使用Spring配置文件实现AOP
2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑实现 (需要知道原理的请看spring aop源码,此处不做赘述) 3、可在现有源码上快速进行功能扩展 4、spring boot,mybatis,druid,spring aop的使用
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供...
Spring Aop 引用 源码
Spring AOP配置的实例,最基本的Spring AOP配置
spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop spring aop
介绍了springAop默认代理方式
里面包括4个例子:(1)Spring实现AOP方式之一:基于XML配置的Spring AOP (2)Spring实现AOP方式之二:使用注解配置 Spring AOP (3)Spring AOP : AspectJ Pointcut 切点 (4)Spring AOP : Advice 声明 (通知注解)
spring aop jar 包
Spring之AOP配置文件详解.txt Spring之AOP配置文件详解.txt 帮助你更快张握Java的学习!
springAOP配置实现动态代理,有利于熟悉动态代理原理,深入了解spring。
spring-aop-1.1.1.jar spring-aop-1.2.6.jar spring-aop-1.2.9.jar spring-aop-2.0.2.jar spring-aop-2.0.6.jar spring-aop-2.0.7.jar spring-aop-2.0.8.jar spring-aop-2.0.jar spring-aop-2.5.1.jar spring-aop-...
有关于Spring,我们最常用的两个功能就是IOC和AOP,前几篇文章从源码级别介绍了Spring容器如何为我们生成bean及bean之间的依赖关系... 确实,Spring也就是通过这两种方式来实现AOP相关功能,下面就通过源码来简单求证下
spring version: 5.0.0; jdk: 1.8 IOC大致调用顺序(IOC调用的AOP标签解析)
描述一下Spring AOP? 在Spring AOP中关注点(concern)和横切关注点(cross-cutting concern)有什么不同? AOP有哪些可用的实现? Spring中有哪些不同的通知类型(advice types)? Spring AOP 代理是什么? 引介...
里面包含了多种Spring AOP配置,十分详细。