靜態(tài)代理:由程序員創(chuàng)建或特定工具自動(dòng)生成源代碼合砂,再對(duì)其編譯青扔。在程序運(yùn)行前,代理類的.class 文件就已經(jīng)存在了翩伪;
動(dòng)態(tài)代理:在程序運(yùn)行時(shí)微猖,運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。
JDK 的動(dòng)態(tài)代理創(chuàng)建機(jī)制—- 通過(guò)接口
使用 JDK 實(shí)現(xiàn)動(dòng)態(tài)代理缘屹,JDK 的動(dòng)態(tài)代理只能對(duì)實(shí)現(xiàn)了接口的類進(jìn)行代理, 被代理的對(duì)象必須要實(shí)現(xiàn)接口凛剥。看下面的案例轻姿。
public interface IPerson {
void eat();
}
public class Person implements IPerson {
@Override
public void eat() {
System.out.println("人要吃飯!!");
}
}
public class PersonInvocationHandler implements InvocationHandler {
private Person person;
public PersonInvocationHandler(Person person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("人吃飯之前要洗手.....");
Object invoke = method.invoke(person, args);
System.out.println("人吃飯之后要洗碗..."); // 這里可以沒(méi)有返回值, 具體看方法是否需要返回值.
return invoke;
}
}
public class JDKPorxy {
public static void main(String[] args) {
Person p = new Person(); // 這里創(chuàng)建一個(gè)動(dòng)態(tài)代理類. 人要吃飯之前要 洗手, 吃飯之后還有洗碗.
Object o = Proxy.newProxyInstance(p.getClass().getClassLoader(),
p.getClass().getInterfaces(),
new PersonInvocationHandler(p)); // 必須使用接口
IPerson person = (IPerson) o;
person.eat(); //end main
}
}
output:
人吃飯之前要洗手.....
人要吃飯 !!
人吃飯之后要洗碗...
cglib 生成動(dòng)態(tài)代理類的機(jī)制—- 通過(guò)類繼承
JDK 中提供的生成動(dòng)態(tài)代理類的機(jī)制有個(gè)鮮明的特點(diǎn)是: 某個(gè)類必須有實(shí)現(xiàn)的接口犁珠,而生成的代理類也只能代理某個(gè)類接口定義的方法逻炊,比如:如果上面例子的 ElectricCar 實(shí)現(xiàn)了繼承自兩個(gè)接口的方法外,另外實(shí)現(xiàn)了方法 bee() , 則在產(chǎn)生的動(dòng)態(tài)代理類中不會(huì)有這個(gè)方法了犁享!更極端的情況是:如果某個(gè)類沒(méi)有實(shí)現(xiàn)接口余素,那么這個(gè)類就不能同 JDK 產(chǎn)生動(dòng)態(tài)代理了!幸好我們有 cglib炊昆〗暗酰“CGLIB(Code Generation Library),是一個(gè)強(qiáng)大的凤巨,高性能视乐,高質(zhì)量的 Code 生成類庫(kù),它可以在運(yùn)行期擴(kuò)展 Java 類與實(shí)現(xiàn) Java 接口磅甩〈读郑”
public class User {
public void eat() {
System.out.println("人要吃飯!!");
}
}
實(shí)現(xiàn)方法的攔截器
public class CGlibInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy)
throws Throwable {
System.out.println("人吃飯之前要洗手.....");
Object invoke = proxy.invokeSuper(obj, args);
System.out.println("人吃飯之后要洗碗..."); // 這里可以沒(méi)有返回值, 具體看方法是否需要返回值.
return invoke;
}
}
public class CGlibProxy {
public static void main(String[] args) {
User user = new User();
//cglib 中加強(qiáng)器,用來(lái)創(chuàng)建動(dòng)態(tài)代理
Enhancer enhancer = new Enhancer();
// 設(shè)置要?jiǎng)?chuàng)建動(dòng)態(tài)代理的類
enhancer.setSuperclass(user.getClass());
// 設(shè)置回調(diào)(方法攔截器)卷要,這里相當(dāng)于是對(duì)于代理類上所有方法的調(diào)用渣聚,都會(huì)調(diào)用 CallBack,而 Callback 則需要實(shí)行 intercept() 方法進(jìn)行攔截
enhancer.setCallback(new CGlibInterceptor());
User u = (User) enhancer.create();
u.eat();
//end main
}
}
output:
人吃飯之前要洗手.....
人要吃飯 !!
人吃飯之后要洗碗...