Spring-AOP(面向切面)

JasonTam發表於2018-08-16

Spring提供了對物件進行AOP程式設計.Spring本身並不是AOP(簡單來說就是spring能幫我們產生代理物件)

AOP:橫向重複,縱向抽取.(Filter過濾器,Interceptor攔截器,Proxy動態代理)

spring實現aop的原理

動態代理

被代理的物件必須實現介面,才能產生代理物件.如果沒有介面將不能使用動態代理技術
public class UserServiceProxyFactory {
    
	private UserService service;
	
    	
	public UserServiceProxyFactory(UserService service) {
		super();
		this.service = service;
	}

	public UserService getUserServiceProxy(){
		
		UserService us = (UserService) Proxy.newProxyInstance(this.getClass().getClassLoader(),UserServiceImpl.class.getInterfaces(),new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				
				System.out.println("start transaction");
				Object invoke = method.invoke(service, args);
				System.out.println("commit transaction");
				return invoke;
			}
		});
		
		return us;
	}

	
} 
複製程式碼

cglib代理

第三方代理技術,可以對任何類進行代理.代理的原理是對被代理物件進行繼承.如果目標物件被final物件修飾,那麼該類將無法被cglib代理
public class UserProxyFactory {

	public UserService getUserServiceProxy() {

		Enhancer en = new Enhancer(); // 生成代理物件

		en.setSuperclass(UserServiceImpl.class);

		en.setCallback(new MethodInterceptor() {

			@Override
			public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {
				System.out.println("start transaction");
				Object invokeSuper = proxy.invokeSuper(obj, arg2);
				System.out.println("commit transaction");
				return invokeSuper;
			}
		});

		UserService obj = (UserService) en.create();

		return obj;
	}
}
複製程式碼

那麼spring是使用了哪一個技術呢?

兩種都使用了,根據情況來決定使用了哪一種技術,如果目標物件有介面就優先使用動態代理技術,如果沒有介面就使用cglib代理

動態代理強調的是介面,cglib代理強調的是對目標物件的繼承.

Spring中的aop名詞

名詞 含義
joinpoint(連線點) 目標物件中,所有可以增強的方法
Pointcut(切入點) 目標物件,已經被增強的方法
Advice(通知/增強) 增強的程式碼
Target(目標) 被代理的物件
Weaving(織入) 將通知應用到切入點的過程
Proxy (代理) 將通知織入目標物件之後,形成代理物件
aspect(切面) 切入點+通知

Spring-Aop的配置(xml配置)

1. 導包&&匯入約束
  • 基礎4個元件包+2個日誌包+

spring-aspects-4.2.4.RELEASE.jar

image

spring-aop-4.2.4.RELEASE.jar

image

com.springsource.org.aopalliance-1.0.0.jar

image

com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

image

  • 匯入約束

約束檔案:spring-aop-4.2.xsd

字首為:aop

image

2. 準備目標物件

填寫要被代理的目標物件.

3. 準備通知(advice)

準備增強的程式碼

image

4. 配置進行織入,將通知應用到切入點的過程
  1. 配置目標物件
  <bean name="UserService" class="com.demo.service.UserServiceImpl"></bean>
複製程式碼
  1. 配置通知
 <bean name="MyAdvice" class="com.demo.aspect.MyAdvice"></bean> 
複製程式碼
  1. 配置切入點
  <aop:config>
       <aop:pointcut expression="execution(* com.demo.service.*ServiceImpl.*(..))" id="pc"/>
       <aop:aspect ref="MyAdvice">
            <aop:after method="after" pointcut-ref="pc"/>
            
       </aop:aspect>
   </aop:config>
複製程式碼
  • 切入點表示式

execution(表示式) 表示式: [方法訪問修飾符] 方法返回值 包名.類名.方法名(方法的引數)

public * cn.demo.spring.dao.*.*(..)
* cn.demo.spring.dao.*.*(..)
* cn.demo.spring.dao.UserDao+.*(..)
* cn.demo.spring.dao..*.*(..)
複製程式碼

Spring-aop(註解配置)

@EnableAspectJAutoProxy註解:開啟aop支援,相當於xml檔案中的aop:aspectj-autoproxy</aop:aspectj-autoproxy>標籤

配置檔案
      <!--  <context:component-scan base-package="com.demo.service"></context:component-scan> -->
       <!--1. config the target  -->
       <bean name="UserService" class="com.demo.service.UserServiceImpl"></bean>
       <!--2. config the advice  -->
       <bean name="myAdvice" class="com.demo.aspect.MyAdvice"></bean>
       <!--3. config the Pointcut 開啟spring對aop註解的支援 -->
       <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
複製程式碼
通知類
 @Aspect
public class MyAdvice {
    
	@Pointcut("execution(* com.demo.service.*ServiceImpl.*(..))")
	public void pc(){}
	
	
	@Before("MyAdvice.pc()")
	public void before() {
		System.out.println("前置通知");
	}
     
	@After("MyAdvice.pc()")
	public void after() {
		System.out.println("後置通知");
	}

	@Around("MyAdvice.pc()")
	public void around(ProceedingJoinPoint pjp) throws Throwable {

		System.out.println("環繞通知前部分");
		Object proceed = pjp.proceed();
		System.out.println("環繞通知後部分");
	}
    
    
	public void beforeException() {
		System.out.println("前置通知,就算出現異常也會呼叫");
	}

	public void afterException() {
		System.out.println("後置通知,就算出現異常也會呼叫");
	}
}
複製程式碼

相關文章