基於註解的面向切面編程aspect注意點

基於註解的面向切面的編程在使用的時候對應的代碼如下:

/**
 * AsyncLoadHandlerAop.java
 * author: yujiakui
 * 2018年4月17日
 * 下午6:44:08
 */
package com.alibaba.asyncload.impl.annotation;

import java.text.MessageFormat;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

import com.alibaba.asyncload.impl.util.MethodFilterUtil;

/**
 * @author yujiakui
 *
 *         下午6:44:08
 *
 *         異步加載處理aop
 *
 */
// 使用cglib代理生成目標類,如果不指定則默認是jdk proxy方式,注意兩者的區別
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Component
@Aspect
public class AsyncLoadHandlerAop {

	/** logger */
	private static final Logger LOGGER = LoggerFactory.getLogger(AsyncLoadHandlerAop.class);

	/** 異步加載處理工廠類 */
	@Autowired
	private AsyncLoadHandleFactory asyncLoadHandleFactory;

	@Pointcut("@within(com.alibaba.asyncload.impl.annotation.AsyncClass)")
	public void aspectjMethod() {
	}

	/**
	 * Around 手動控制調用核心業務邏輯,以及調用前和調用後的處理,
	 *
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around(value = "aspectjMethod()")
	public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
		LOGGER.info("coming-------------");
		// 對方法進行過濾
		if (MethodFilterUtil.filterMethod(pjp)) {
			return pjp.proceed();
		} else {
			LOGGER.info(MessageFormat.format("異步並行框架處理開始pjp={0}", pjp.toShortString()));
			return asyncLoadHandleFactory.handle(pjp);
		}
	}
}

對應的註解AsyncClass代碼如下:

/**
 * AsyncClass.java
 * author: yujiakui
 * 2018年4月17日
 * 下午3:06:31
 */
package com.alibaba.asyncload.impl.annotation;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(RUNTIME)
@Target({ TYPE })
@Inherited
/**
 * @author yujiakui
 *
 *         下午3:06:31
 *
 */
public @interface AsyncClass {

	/**
	 * 異步方法列表
	 *
	 * @return
	 */
	AsyncMethod[] asyncMethods() default {};

	/**
	 * 類級別線程池配置
	 *
	 * @return
	 */
	AsyncThreadPoolConfig classThreadPoolConf() default @AsyncThreadPoolConfig;

}

對應的項目pom.xml配置要增加如下內容:

<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.3.11.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.10</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.8.10</version>
		</dependency>

		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.1</version>
		</dependency>

測試代碼如下:

/**
 * AsyncLoadAnnotationTest.java
 * author: yujiakui
 * 2018年4月18日
 * 下午3:25:33
 */
package com.alibaba.asyncload.annotation;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.alibaba.asyncload.domain.AsyncLoadTestModel;

import junit.framework.Assert;

/**
 * @author yujiakui
 *
 *         下午3:25:33
 *
 */
public class AsyncLoadAnnotationTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(
				"com.alibaba.asyncload.impl.annotation", "com.alibaba.asyncload.annotation",
				"com.alibaba.asyncload.domain");
		System.out.println(annotationConfigApplicationContext.getBeanDefinitionNames());

		// 執行測試
		AsyncLoadAnnotationTestServiceImpl service = annotationConfigApplicationContext
				.getBean(AsyncLoadAnnotationTestServiceImpl.class);
		

	}
}

(1) 如果AsyncLoadAnnotationTestServiceImpl  實現的有對應的接口且在切面中沒有指定proxyTargetClass,則在spring 容器中AsyncLoadAnnotationTestServiceImpl  對應的bean是使用jdk proxy實現的,此時運行這行代碼就會報錯:

AsyncLoadAnnotationTestServiceImpl service = annotationConfigApplicationContext
				.getBean(AsyncLoadAnnotationTestServiceImpl.class);

異常信息如下:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.alibaba.asyncload.annotation.AsyncLoadAnnotationTestServiceImpl' available
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
	at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1090)
	at com.alibaba.asyncload.annotation.AsyncLoadAnnotationTest.main(AsyncLoadAnnotationTest.java:33)

(2) 如果AsyncLoadAnnotationTestServiceImpl沒有實現接口,且不需要在切面中指定proxyTargetClass=true,也是使用cglib進行代理

(3)如果指定@EnableAspectJAutoProxy(proxyTargetClass = true) 則不管什麼情況都是cglib進行代理。

cglib代理和jdk proxy代理的區別如下:

cglib代理是直接生產對應的類的子類,所以你使用getbean方法可以獲得,而jdk的proxy使用是代理模式(和目標類實現同一個接口,所以你使用目標類型進行getbean肯定是得不到的,但是如果使用接口類型進行getbean就可以獲取到)






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章