1. 程式人生 > >Spring AOP程式設計(二)-AOP實現的三種方式

Spring AOP程式設計(二)-AOP實現的三種方式

AOP的實現有三種方式:

l         aop底層將採用代理機制進行實現。

l         介面 + 實現類 :spring採用 jdk 的動態代理Proxy。

l         實現類:spring 採用 cglib位元組碼增強。

 

一.手工方式

1.JDK動態代理

JDK動態代理 對“裝飾者”設計模式 簡化。使用前提:必須有介面

1.目標類:介面 + 實現類

2.切面類:用於存通知 MyAspect

3.工廠類:編寫工廠生成代理

4.測試

1.目標類

UserService.java

package com.zk.a_jdk;

public interface UserService {
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy deleteUser");
	}

}

2.切面類

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {
	
	public void before(){
		System.out.println("雞頭");
	}
	
	public void after(){
		System.out.println("牛後");
	}
}

3.工廠

package com.zk.a_jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanFactory {
	//手工代理
	public static UserService createService(){
		//1.目標類
		final UserService userservice=new UserServiceImpl();
		//2.切面類
		final MyAspect myAspect=new MyAspect();
		//3.代理類:將目標類(切入點)和切面類(通知)結合-->切面
		//Proxy.newProxyInstance
		/*
		 * 引數一:loader類載入器,動態代理類,執行時建立,任何類都需要類載入器將其載入至記憶體。
		 * 一般情況下:當前類,class.getClassLoader();
		 * 目標類例項:getClass().get...
		 * 引數二:interfaces,代理類需要實現的所有介面
		 * 方式一:目標類例項.getClass().getInterfaces();注意:只能獲得自己的介面,獲得不到父元素的介面
		 * 方式二:new Class[]{UserService.class}
		 * 例如:jdbc驅動
		 * 引數三:InvocationHandler 處理類,介面,必須進行實現類,一般採用匿名內部類
		 * 提供invoke方法,代理類每一個方法執行時,都將去呼叫invoke
		 * 引數三.1.Object proxy代理物件
		 * 引數三.2.Method method 代理物件當前方法的描述物件(反射)
		 * 執行方法方法名:method.getName();
		 * 執行方法:method.invoke(物件,實際引數)
		 * 引數三.3 Object[] args 方法實際引數
		 */
		UserService proxyService=(UserService)Proxy.newProxyInstance
				(MyBeanFactory.class.getClassLoader(), 
						userservice.getClass().getInterfaces(), new InvocationHandler(){

							@Override
							public Object invoke(Object proxy, Method method,
									Object[] args) throws Throwable {
								// TODO Auto-generated method stub
								
								//前執行
								myAspect.before();
								//執行目標類的方法
								Object obj=method.invoke(userservice, args);
								
								//後執行
								myAspect.after();
								
								return null;
							}
				});
		return proxyService;
	}
}

4.測試類

package com.zk.a_jdk;

import org.junit.Test;

public class TestJDK {

	@Test
	public void test(){
		UserService userservice=MyBeanFactory.createService();
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

執行效果:

2.  CGLIB位元組碼增強

l         沒有介面,只有實現類。

l         採用位元組碼增強框架 cglib,在執行時 建立目標類的子類,從而對目標類進行增強。

l         匯入jar包:

 

1.目標類

UserService.java

package com.zk.a_jdk;

public interface UserService {
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

UserServiceImpl.java

package com.zk.a_jdk;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("proxy deleteUser");
	}

}

2.切面類

MyAspect.java

package com.zk.a_jdk;

public class MyAspect {
	
	public void before(){
		System.out.println("雞頭");
	}
	
	public void after(){
		System.out.println("牛後");
	}
}

3.MyBeanFactory.java工廠類

package com.zk.b_cglib;


import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;


public class MyBeanFactory {
	//手工代理
	public static UserService createService(){
		//1.目標類
		final UserServiceImpl userservice=new UserServiceImpl();
		//2.切面類
		final MyAspect myAspect=new MyAspect();
		/*3.代理類
		 * 採用位元組碼增強框架-cglib,程式執行時建立目標類的子類,從而對目標類進行增強
		 * 匯入jar包
		 * intercept等效於jdk中invoke方法
		 * 引數一二三 與invoke相同
		 * 引數四方法的代理
		 */
		Enhancer enhance=new Enhancer();
		//確定父類
		enhance.setSuperclass(userservice.getClass());
		enhance.setCallback(new MethodInterceptor(){
			//設定回撥函式,MethodInterceptor介面等效 jdk InvocationHandler介面
			@Override
			public Object intercept(Object proxy, Method method, Object[] args,
					MethodProxy methodproxy) throws Throwable {
				// TODO Auto-generated method stub
				//前before
				myAspect.before();
				//執行目標類的方法
				Object obj=method.invoke(userservice, args);
				//執行代理類的父類
				methodproxy.invokeSuper(proxy, args);
				//後after
				myAspect.after();
				return null;
			}

			
		});
		//建立代理
		UserServiceImpl proxyservice=(UserServiceImpl) enhance.create();
		return proxyservice;
	}
}

 

 4.TestCglib.java測試

package com.zk.b_cglib;

import org.junit.Test;

public class Testcglib {

	@Test
	public void test(){
		UserService userservice=MyBeanFactory.createService();
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

 

執行效果圖:

 

二.半自動方式

讓spring 建立代理物件,從spring容器中手動的獲取代理物件。

匯入jar包:

 

AOP:AOP聯盟(規範)、spring-aop (實現)

1.目標類

UserService.java

public interface UserService {	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

 

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("deleteUser");
	}

}

2.切面類

/**
 * 切面類中確定通知,需要實現不同介面,介面就是規範,從而就確定方法名稱。
 * * 採用“環繞通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		
		//手動執行目標方法
		Object obj = mi.proceed();
		
		System.out.println("後3");
		return obj;
	}
}

 

3.spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">
    <!-- 建立目標類 -->
    <bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean>
    
    <!-- 建立切面類 -->
    <bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean>
    
    <!-- 建立代理類
                 使用工廠bean factorybean,底層呼叫getObject(), 返回特殊bean
      ProxyBeanFactory用於建立代理工廠bean,生成特殊代理物件
      interface確定介面
                  通過Array確定多個值
                  只有一個值時,value=""
      target確定目標類
      interceptorNames:通知切面類名稱,型別String[],如果設定一個值, value=""
      optimize:強制使用cglib
      <property name="optimized value="true"></property>
      底層機制:
      如果目標類有介面,採用jdk代理
      如果沒有介面,採用cglib代理
      如果宣告式optimize=true,都使用cglib
     -->
    <bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interfaces" value="com.zk.factorybean.UserService"></property>
    <property name="target" ref="userserviceid"></property>
    <property name="interceptorNames" value="aspectid"></property>
    </bean>
</beans>

  

4.Testfactorybean.java

package com.zk.factorybean;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Testfactorybean {

	@Test
	public void test(){
		String path="com/zk/factorybean/ApplicationContext.xml";
		ApplicationContext ac=new ClassPathXmlApplicationContext(path);
		UserService userservice=(UserService) ac.getBean("proxyServiceid");
		userservice.addUser();
		userservice.deleteUser();
		userservice.updateUser();
	}
}

  

執行效果:

 

三.spring aop程式設計:全自動

從spring容器獲得目標類,如果配置aop,spring將自動生成代理。

要確定目標類,aspectj 切入點表示式,匯入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

 

1.目標類

UserService.java

public interface UserService {	
	public void addUser();
	public void updateUser();
	public void deleteUser();
}

 

UserServiceImpl.java

package com.zk.springAop;

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		// TODO Auto-generated method stub
		System.out.println("addUser");
	}

	@Override
	public void updateUser() {
		// TODO Auto-generated method stub
		System.out.println("updateUser");
	}

	@Override
	public void deleteUser() {
		// TODO Auto-generated method stub
		System.out.println("deleteUser");
	}

}

2.切面類

/**
 * 切面類中確定通知,需要實現不同介面,介面就是規範,從而就確定方法名稱。
 * * 採用“環繞通知” MethodInterceptor
 *
 */
public class MyAspect implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		System.out.println("前3");
		
		//手動執行目標方法
		Object obj = mi.proceed();
		
		System.out.println("後3");
		return obj;
	}
}

3.spring配置

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.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.xsd
    ">
    <!-- 建立目標類 -->
    <bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean>
    
    <!-- 建立切面類 -->
    <bean id="aspectid" class="com.zk.springAop.MyAspect"></bean>
    
    <!-- Aop程式設計
    1.匯入名稱空間
    2.使用<aop:config>進行配置
    proxy-target-class="true"宣告是使用cglib代理
    <aop:pointcut>:切入點,從目標物件上獲取具體的方法
    <aop:advisor>特殊的切面,只有一個通知和一個切入點
    advise-ref 通知引用
    pointcut-ref 切入點引用
    advisor通知
    3.切入點表示式
    execution(* com.zk.springAop.*.*(..))
    選擇方法 *表示返回值任意    包                                      類名任意. 方法名任意 . 引數任意 .
        -->
    <aop:config>
    <aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/>
    <aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/>
    </aop:config> 
</beans>