反射就是在運行時才知道要操作的類是什么,并且可以在運行時獲取類的完整構造,并呼叫對應的方法,
JDK的java.lang.reflect包提供了反射支持,
1.Class類
程式運行期間,Java會給每個物件都維護一個運行時型別標識,該物件保存著該類的資訊,
三種獲取Class類的方法:
- object.getClass()
- Class.forName(類的全路徑名)
- Employee.class
2.反射
java.lang.reflect包下有三個類Field、Method、Constructor分別描述了域、方法、構造器,可以獲取類的所有資訊,
Class類的getFields、getMethods、getConstructors方法會回傳回應的的資訊,
兩個簡單例子
下面實作了兩個相同的操作,不同的是在反射中我們可以事先沒有得到該類,通過反射的方法去new 實體,并呼叫方法,
3.動態代理
代理類在程式運行時完成創建的代理方式被成為動態代理,
動態代理相對于靜態代理來說,耦合性更低,像靜態代理如果需要代理100個介面,就得寫100個代理類,而動態代理只需要一個,
3.1 JDK動態代理
介面以及被代理物件
public interface House {
void sell();
}
public class Bieshu implements House{
@Override
public void sell() {
System.out.println("賣了大別墅~");
}
}
InvocationHandler
public class HouseHandler implements InvocationHandler {
private Object obj;
public HouseHandler(Object obj){
super();
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
System.out.println("出售前~");
method.invoke(obj);
System.out.println("出售后~");
return null;
}
}
main方法
public static void main(String[] args) {
Bieshu bieshu = new Bieshu();
HouseHandler houseHandler = new HouseHandler(bieshu);
Class<?> bieshuClass = bieshu.getClass();
House proxyInstance = (House) Proxy.newProxyInstance(bieshuClass.getClassLoader(), bieshuClass.getInterfaces(), houseHandler);
proxyInstance.sell();
}
--------------------------------
出售前~
賣了大別墅~
出售后~
所以總的來說JDK代理就是兩層代理,Proxy代理了InvocationHandler,而InvocationHandler代理了被代理類,
3.2 CGLib代理
代理的目的是構造一個和被代理物件有相同行為的物件,所以不一定需要通過持有的方式來實作,也可以通過繼承,并重寫父類方法來實作,CGLib就是如此,
被代理類
public class HelloService {
public HelloService() {
System.out.println("HelloService構造");
}
/**
* 該方法不能被子類覆寫,Cglib是無法代理final修飾的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>" + name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
MethodInterceptor
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
// 這里增強
System.out.println("收錢");
return arg3.invokeSuper(arg0, arg2);
}
}
main
public static void main(String[] args) {
// 通過CGLIB動態代理獲取代理物件的程序
Enhancer enhancer = new Enhancer();
// 設定enhancer物件的父類
enhancer.setSuperclass(HelloService.class);
// 設定enhancer的回呼物件
enhancer.setCallback(new MyMethodInterceptor());
// 創建代理物件
HelloService proxy= (HelloService)enhancer.create();
// 通過代理物件呼叫目標方法
proxy.sayHello();
}
3.3 兩者的區別
-
JDK動態代理是面向介面的
-
CGLib動態代理是通過位元組碼底層繼承來實作的,
-
spring中當被代理類是實作類就會使用JDK代理,否則則用CGLib
-
CGLib創建動態代理物件在運行中比JDK代理的快很多,所以使用單例時比較適合,
-
CGLib創建動態代理物件在創建中比JDK代理的慢很多
-
目前隨著JDK的版本提高,JDK動態代理的效率已經比CGLib高了,
public class ReflectTest {
public static class BasketBall{
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 1.正常呼叫
BasketBall basketBall = new BasketBall();
basketBall.setPrice(10);
// 2.反射呼叫
System.out.println(basketBall.getClass().getName());
String name = "reflect.ReflectTest$BasketBall";
Class classBasketBall = Class.forName(name);
Method method = classBasketBall.getMethod("setPrice", int.class);
Constructor constructor = classBasketBall.getConstructor();
Object instance = constructor.newInstance();
method.invoke(instance,10);
}
}
3.4 AOP
AOP(Aspect-OrientedProgramming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向物件編程)的補充和完善,在OOP中允許定義從上到下的關系,但是對橫向關系就無能為力了,AOP就提供了橫向的處理能力,比如說日志,權限校驗等功能會橫切在代碼中,這會導致代碼不能復用,
spring 通過動態代理實作了AOP,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299543.html
標籤:其他
下一篇:JDK 1.8新特性
