1. 程式人生 > >Spring底層AOP的原理示例(JDK動態代理和cglib動態代理)

Spring底層AOP的原理示例(JDK動態代理和cglib動態代理)

1 JDK動態代理(必須要有介面)

  • 介面
package com.itykd.dao;

public interface UserDao {
	void save();
	void update();
	void find();
	void delete();
}
  • 實現類
package com.itykd.dao.impl;

import com.itykd.dao.UserDao;

public class UserDaoImpl implements UserDao {

	@Override
	public void save() {
		System.out.println("UserDaoImpl的save方法執行了.....");
		
	}

	@Override
	public void update() {
		System.out.println("UserDaoImpl的update方法執行了.....");
		
	}

	@Override
	public void find() {
		System.out.println("UserDaoImpl的find方法執行了.....");
		
	}

	@Override
	public void delete() {
		System.out.println("UserDaoImpl的delete方法執行了.....");
		
	}

}
  • 提供一個JDK代理類需要繼承InvocationHandler介面,並實現invoke方法,這裡對Dao的save方法進行增強,Proxy的newProxyInstance方法提供三個引數建立UserDao物件,第一個引數是類載入器,第二個引數是介面
package com.itykd.proxy;

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

import com.itykd.dao.UserDao;

public class JDKProxy implements InvocationHandler{
	
	//將被增強的物件傳遞到代理中
	private UserDao userDao;
	
	
	public JDKProxy(UserDao userDao) {
		super();
		this.userDao = userDao;
	}
	public UserDao createProxy() {
		UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
		return userDaoProxy;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//判斷方法是否是save
		if("save".equals(method.getName())) {
			//增強
			System.out.println("許可權校驗......");
			return method.invoke(userDao, args);
		}
		return method.invoke(userDao, args);
	}

}
  • 測試程式碼
package com.itykd.proxy;

import org.junit.Test;

import com.itykd.dao.UserDao;
import com.itykd.dao.impl.UserDaoImpl;

public class ProxyDemo {
	@Test
	public void jdkProxyDemo() {
		UserDao userDao = new UserDaoImpl();
		//建立代理
		UserDao userDaoProxy = new JDKProxy(userDao).createProxy();
		userDaoProxy.save();
		userDaoProxy.find();
		userDaoProxy.delete();
		userDaoProxy.update();
	}
}

2 Cglib動態代理(繼承的形式生成代理物件)

cglib是第三方開原始碼生成類庫,動態新增類的屬性和方法(原來Hibernate也是用cglib做延遲載入,現在使用的是Javassist技術),Spring的核心包下已經有了Cglib的環境

  • 目標類(要增強的類)
package com.itykd.dao;

public class ProductDao {
	public void save() {
		System.out.println("ProductDao的save方法執行了....");
	}
	public void update() {
		System.out.println("ProductDao的update方法執行了....");
	}
	public void delete() {
		System.out.println("ProductDao的delete方法執行了....");
	}
	public void find() {
		System.out.println("ProductDao的find方法執行了....");
	}
}
  • cglib代理類
package com.itykd.proxy;

import java.lang.reflect.Method;

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

import com.itykd.dao.ProductDao;

public class CglibProxy implements MethodInterceptor{

	private ProductDao productDao;
	
	public CglibProxy(ProductDao productDao) {
		super();
		this.productDao = productDao;
	}
	public ProductDao createProxy() {
		//1 建立cglib的核心類物件
		Enhancer enhancer = new Enhancer();
		//2 設定父類
		enhancer.setSuperclass(productDao.getClass());
		//3 設定回撥:(類似於InvocationHandler物件)
		enhancer.setCallback(this);
		//4 建立代理物件
		ProductDao productDaoProxy = (ProductDao)enhancer.create();
		return productDaoProxy;
	}

	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		//判斷方法是否為save
		if("save".equals(method.getName())) {
			//增強
			System.out.println("許可權校驗...........");
			return methodProxy.invokeSuper(proxy, args);
		}
		return methodProxy.invokeSuper(proxy, args);
	}
}
  • 測試類
package com.itykd.proxy;

import org.junit.Test;
import com.itykd.dao.ProductDao;

public class ProxyDemo {	
    public void cglibProxyDemo() {
		ProductDao productDao = new ProductDao();
		ProductDao productDaoProxy = new CglibProxy(productDao).createProxy();
		productDaoProxy.save();
		productDaoProxy.find();
		productDaoProxy.delete();
		productDaoProxy.update();
		
	}
}