系列閱讀
- Java基礎:類加載器
- Java基礎:反射
- Java基礎:注解
- Java基礎:動态代理
概述
在運作時,動态建立一組指定的接口的實作類對象(代理對象)!
代理是實作AOP(面向切面程式設計)的核心和關鍵技術,動态代理的用途與裝飾模式很相似,就是為了對某個對象進行增強。所有使用裝飾者模式的案例都可以使用動态代理來替換。
代理:本來應該自己做的事情,卻請了别人來做,被請的人就是代理對象。
舉例:春季回家買票讓人代買
動态代理:在程式運作過程中産生的這個對象
而程式運作過程中産生對象其實就是我們剛才反射講解的内容,是以,動态代理其實就是通過反射來生成一個代理
工作原理
- client調用代理
- 代理的構造方法接收一個invocationhandler參數
- client調用代理的各個方法,代理的各個方法會把調用請求轉發給invocationhandler
- invocationhandler通過invoke()方法把調用請求分發給目标對象的各個方法
1、在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過使用這個類和接口就可以生成動态代理對象。JDK提供的代理隻能針對接口做代理。我們有更強大的代理cglib。
2、Proxy類中的方法建立動态代理類對象
public static Object newProxyInstance(
ClassLoader loader,
Class<?>[]interfaces,
InvocationHandler h)
傳回一個指定接口的代理類執行個體,該接口可以将方法調用指派到指定的調用處理程式。最終會調用InvocationHandler的方法
3、InvocationHandler
Object invoke(Object proxy,Method method,Object[] args)
在代理執行個體上處理方法調用并傳回結果。
4、Proxy類中建立動态代理對象的方法的三個參數
-
ClassLoader對象
定義了由哪個ClassLoader對象來對生成的代理對象進行加載
-
Interface對象的數組
表示的是我将要給我需要代理的對象提供一組什麼接口,如果我提供了一組接口給它,那麼這個代理對象就宣稱實作了該接口(多态),這樣我就能調用這組接口中的方法了
-
InvocationHandler對象
表示的是當我這個動态代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上
每一個動态代理類都必須要實作InvocationHandler這個接口,并且每個代理類的執行個體都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由InvocationHandler這個接口的invoke 方法來進行調用。
5、InvocationHandler接口中invoke()方法的三個參數:
- Object proxy:代表動态代理對象
- Method method:代表正在執行的方法
- Object[] args:代表調用目标方法時傳入的實參
6、Proxy.newProxyInstance()
建立的代理對象是在jvm運作時動态生成的一個對象,它并不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運作是動态生成的一個對象,并且命名方式都是這樣的形式,以$開頭,proxy為中,最後一個數字表示對象的标号
動态代理的實作
package cn.itcast_06;
/*
* 使用者操作接口
*/
public interface UserDao {
public abstract void add();
public abstract void delete();
public abstract void update();
public abstract void find();
}
package cn.itcast_06;
public interface StudentDao {
public abstract void login();
public abstract void regist();
}
package cn.itcast_06;
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("添加功能");
}
@Override
public void delete() {
System.out.println("删除功能");
}
@Override
public void update() {
System.out.println("修改功能");
}
@Override
public void find() {
System.out.println("查找功能");
}
}
package cn.itcast_06;
public class StudentDaoImpl implements StudentDao {
@Override
public void login() {
System.out.println("登入功能");
}
@Override
public void regist() {
System.out.println("注冊功能");
}
}
package cn.itcast_06;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target; // 目标對象
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("權限校驗");
Object result = method.invoke(target, args);
System.out.println("日志記錄");
return result; // 傳回的是代理對象
}
}
package cn.itcast_06;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
ud.add();
ud.delete();
ud.update();
ud.find();
System.out.println("-----------");
// 我們要建立一個動态代理對象
// Proxy類中有一個方法可以建立動态代理對象
// public static Object newProxyInstance(ClassLoader loader,Class<?>[]
// interfaces,InvocationHandler h)
// 我準備對ud對象做一個代理對象
MyInvocationHandler handler = new MyInvocationHandler(ud);
UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass()
.getClassLoader(), ud.getClass().getInterfaces(), handler);
proxy.add();
proxy.delete();
proxy.update();
proxy.find();
System.out.println("-----------");
StudentDao sd = new StudentDaoImpl();
MyInvocationHandler handler2 = new MyInvocationHandler(sd);
StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass()
.getClassLoader(), sd.getClass().getInterfaces(), handler2);
proxy2.login();
proxy2.regist();
}
}
Spring原理
public class ProxyFactoryBean {
private Object mTarget;
private Advice mAdvice;
public Object getProxy(){
Object proxy = Proxy.newProxyInstance(
mTarget.getClass().getClassLoader(),
mTarget.getClass().getInterfaces(),
mHandler
);
return proxy;
}
private InvocationHandler mHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
mAdvice.beforeMethod(method);
Object result = method.invoke(mTarget, args);
mAdvice.afterMethod(method);
return result;
}
};
public void setTarget(Object target) {
mTarget = target;
}
public void setAdvice(Advice advice) {
mAdvice = advice;
}
public Object getTarget() {
return mTarget;
}
public Advice getAdvice() {
return mAdvice;
}
}
public class BeanFactory {
Properties mProperties = new Properties();
public BeanFactory(InputStream in){
try {
mProperties.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
public Object getBean(String name){
String classname = mProperties.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(classname);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
if (bean instanceof ProxyFactoryBean){
Object proxy = null;
ProxyFactoryBean factoryBean = (ProxyFactoryBean) bean;
Advice advice = null;
try {
advice = (Advice) Class.forName(mProperties.getProperty(name+".advice")).newInstance();
Object target = Class.forName(mProperties.getProperty(name+".target")).newInstance();
factoryBean.setAdvice(advice);
factoryBean.setTarget(target);
proxy = factoryBean.getProxy();
} catch (Exception e) {
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}
public class AopFrameworkTest {
public static void main(String[] args) throws Exception {
InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
Object bean = new BeanFactory(ips).getBean("xxx");
System.out.println(bean.getClass().getName());
((Collection)bean).clear();
}
}