1. 程式人生 > >Spring aop利用jdk的InvocationHandler產生動態代理

Spring aop利用jdk的InvocationHandler產生動態代理

筆記之用……

首先有一個介面UserService

package com.spring.test;

import org.springframework.stereotype.Component;

@Component
public interface UserService {
	
	public void createUser();
	
	public void deleteUser();
	
	public void updateUser(int id);

}

UserDao實現UserService

package com.spring.test;

import org.springframework.stereotype.Component;

@Component
public class UserDao implements UserService {

	public void createUser() {
		System.out.println("user saved...");

	}
	
	public void deleteUser(){
		System.out.println("delete user...");
	}
	
	public void updateUser(int id){
		System.out.println("update user...");
	}

}

想要在這些方法執行的時候加一些業務邏輯,如公共日誌或者計算方法執行前後的時間等,將程式碼以切面的形式切入到方法中,此時可以用動態代理來實現,

aop的動態代理底層是用jdk的動態代理實現的proxy和InvocationHandler,需實現 java.lang.reflect.InvocationHandler

首先定義一個LogInteceptor來實現InvocationHandler:

package com.spring.log;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Calendar;
import java.util.Date;

/*****************
 * 日誌類
 * 
 * @author Administrator
 * 
 */
public class LogInteceptor implements InvocationHandler{

	private Object target;//被代理的物件
	
	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		beforeMethod(method);//在方法執行前所要執行的業務邏輯
		long starttime=System.currentTimeMillis();
		method.invoke(target, args);
		long result=System.currentTimeMillis()-starttime;
		System.out.println("執行時間為:"+result+"毫秒");
		afterMethod(method);//在方法執行後所要執行的業務邏輯
		return null;
	}
	
	public void beforeMethod(Method m){
		System.out.println(m.getName()+"執行before....");
	}
	
	public void afterMethod(Method m){
		System.out.println(m.getName()+"執行after...");
	}

}

然後用JUnit來進行測試

package com.junit.test;

import java.lang.reflect.Proxy;

import com.spring.log.LogInteceptor;
import com.spring.test.UserDao;
import com.spring.test.UserService;


public class Test {
	
	
	@org.junit.Test
	public void testProxy(){
		
		UserDao userDao=new UserDao();//被代理的物件
		LogInteceptor logInteceptor=new LogInteceptor();//獲取日誌的InvocationHandler
		logInteceptor.setTarget(userDao);//把被代理的物件設為userDao
		
		//設定代理物件,引數1:被代理物件的classloader,引數2:被代理物件所實現的介面(該物件必須要實現介面,不然無法產生代理),引數3:指定處理的InvocationHandler
		UserService userService=(UserService)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), new Class[]{UserService.class}, logInteceptor);
		userService.createUser();//執行方法
		userService.deleteUser();//執行方法
		userService.updateUser(1001);//執行方法
	}

}

執行結果:

createUser執行before....
user saved...
---執行時間為:0毫秒
createUser執行after...
deleteUser執行before....
delete user...
---執行時間為:0毫秒
deleteUser執行after...
updateUser執行before....
update user...
---執行時間為:0毫秒
updateUser執行after...

接下來來點實際的..........................

定義一個LogInterceptor,讓dao裡的方法在執行的前後執行某些特定的方法

package com.spring.log;

public class LogInterceptor {
	
	public void beforeMethod(){
		System.out.println("方法執行前執行");
	}
	
	public void afterMethod(){
		System.out.println("方法執行後執行");
	}

}

定義的beforeMethod和afterMethod在applicationContext.xml裡用aop配置

<bean id="mylog" class="com.spring.log.LogInterceptor"></bean>
	<aop:config>
		<aop:aspect id="log" ref="mylog">
			<aop:pointcut expression="execution (* com.spring.test.*.*(..))" id="point" /><!--切入點-->
			<aop:before method="beforeMethod"  pointcut-ref="point"/><!-- 定義方法before前執行自己定義的beforeMethod -->
			<aop:after method="afterMethod" pointcut-ref="point"/><!-- 定義方法after後執行自己定義的afterMethod -->
		</aop:aspect>
	</aop:config>

當然還可以配置

<aop:around method=""/>
<aop:after-returning method=""/>
<aop:after-throwing method=""/>

最後用JUnit測試:

@org.junit.Test
	public void Test(){
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("userDao");
		service.createUser();
	}

執行結果:

方法執行前執行
user saved...
方法執行後執行