Spring IOC和AOP

1楼誓、IOC

概念:所謂控制反轉(zhuǎn),就是把原先我們代碼里面需要實(shí)現(xiàn)的對象創(chuàng)建名挥、依賴的代碼疟羹,反轉(zhuǎn)給容器來幫忙實(shí)現(xiàn)。當(dāng)應(yīng)用了IoC禀倔,一個對象依賴的其它對象會通過被動的方式傳遞進(jìn)來榄融,而不是這個對象自己創(chuàng)建或者查找依賴對象。

Spring 啟動時讀取應(yīng)用程序提供的Bean配置信息救湖,并在Spring容器中生成一份相應(yīng)的Bean配置注冊表愧杯,然后根據(jù)這張注冊表實(shí)例化Bean,裝配好Bean之間的依賴關(guān)系鞋既,為上層應(yīng)用提供準(zhǔn)備就緒的運(yùn)行環(huán)境力九。

image.png

1.1 底層實(shí)現(xiàn):

image.png

如果是xml文件,那么需要解析xml文件邑闺;如果是注解跌前,需要通過反射獲取注解,然后根據(jù)獲取到的bean信息通過反射實(shí)例化bean陡舅,實(shí)例化之后將bean放到spring容器的bean緩存池中(hashMap)抵乓,當(dāng)要使用bean時,可以通過applicationContext獲取bean(getBean)。

1.2 spring ioc autowired如何實(shí)現(xiàn)

@Autowired表示被修飾的類需要注入對象灾炭,spring會掃描所有被@Autowired標(biāo)注的類,然后根據(jù) 類型type 在ioc容器中找到匹配的類注入

@Autowired VS @Resource
  • 提供方:@Autowired是由Spring提供茎芋;
    @Resource是由javax.annotation.Resource提供,即J2EE提供咆贬,需要JDK1.6及以上败徊;
  • 注入方式:@Autowired只按照byType 注入;
    @Resource默認(rèn)按byName自動注入掏缎,也提供按照byType 注入皱蹦;

1.3 @component

普通pojo實(shí)例化到spring容器中,相當(dāng)于配置文件中的<bean id="" class=""/>
雖然有了@Autowired,但是我們還是要寫一堆bean的配置文件眷蜈,相當(dāng)麻煩沪哺,而@Component就是告訴spring了袁,我是pojo類畦韭,把我注冊到容器中吧,spring會自動提取相關(guān)信息碌宴。那么我們就不用寫麻煩的xml配置文件了忌怎。

https://zhuanlan.zhihu.com/p/29344811

1.4 bean生命周期

image.png
  • 1.4.1.當(dāng)調(diào)用者通過 getBean(beanName)向容器請求某一個 Bean 時籍滴,如果容器注冊了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor 接口,在實(shí)例化 Bean 之前榴啸,將調(diào)用接口的 postProcessBeforeInstantiation()方法孽惰;
  • 1.4.2.根據(jù)配置情況調(diào)用 Bean 構(gòu)造函數(shù)或工廠方法實(shí)例化 Bean;
  • 1.4.3.如果容器注冊了 InstantiationAwareBeanPostProcessor 接口鸥印,在實(shí)例化 Bean 之后勋功,調(diào)用該接口的 postProcessAfterInstantiation()方法,可在這里對已經(jīng)實(shí)例化的對象進(jìn)行一些“梳妝打扮”库说;
  • 1.4.4.如果 Bean 配置了屬性信息狂鞋,容器在這一步著手將配置值設(shè)置到 Bean 對應(yīng)的屬性中,不過在設(shè)置每個屬性之前將先調(diào)用InstantiationAwareBeanPostProcessor 接口的postProcessPropertyValues()方法潜的;
  • 1.4.5.調(diào)用 Bean 的屬性設(shè)置方法設(shè)置屬性值骚揍;
  • 1.4.6.如果 Bean 實(shí)現(xiàn)了 org.springframework.beans.factory.BeanNameAware 接口,將調(diào)用setBeanName()接口方法夏块,將配置文件中該 Bean 對應(yīng)的名稱設(shè)置到 Bean 中疏咐;
  • 1.4.7.如果 Bean 實(shí)現(xiàn)了 org.springframework.beans.factory.BeanFactoryAware 接口,將調(diào)用 setBeanFactory()接口方法脐供,將 BeanFactory 容器實(shí)例設(shè)置到 Bean 中浑塞;
  • 1.4.8.如果 BeanFactory 裝配了 org.springframework.beans.factory.config.BeanPostProcessor后處理器,將調(diào)用 BeanPostProcessor 的 Object postProcessBeforeInitialization(Object bean, String beanName)接口方法對 Bean 進(jìn)行加工操作政己。其中入?yún)?bean 是當(dāng)前正在處理的 Bean酌壕,而 beanName 是當(dāng)前 Bean 的配置名掏愁,返回的對象為加工處理后的 Bean。用戶可以使用該方法對某些 Bean 進(jìn)行特殊的處理卵牍,甚至改變 Bean 的行為果港, BeanPostProcessor 在 Spring 框架中占有重要的地位,為容器提供對 Bean 進(jìn)行后續(xù)加工處理的切入點(diǎn)糊昙, Spring 容器所提供的各種“神奇功能”(如 AOP辛掠,動態(tài)代理等)都通過 BeanPostProcessor 實(shí)施;
  • 1.4.9.如果 Bean 實(shí)現(xiàn)了 InitializingBean 的接口释牺,將調(diào)用接口的 afterPropertiesSet()方法萝衩;
  • 1.4.10.如果在<bean>通過 init-method 屬性定義了初始化方法,將執(zhí)行這個方法没咙;
  • 1.4.11.BeanPostProcessor 后處理器定義了兩個方法:其一是 postProcessBeforeInitialization() 在第 8 步調(diào)用猩谊;其二是 Object postProcessAfterInitialization(Object bean, String beanName)方法,這個方法在此時調(diào)用祭刚,容器再次獲得對 Bean 進(jìn)行加工處理的機(jī)會牌捷;
  • 1.4.12.如果在<bean>中指定 Bean 的作用范圍為 scope=“prototype”,將 Bean 返回給調(diào)用者涡驮,調(diào)用者負(fù)責(zé) Bean 后續(xù)生命的管理暗甥, Spring 不再管理這個 Bean 的生命周期。如果作用范圍設(shè)置為 scope=“singleton”捉捅,則將 Bean 放入到 Spring IoC 容器的緩存池中淋袖,并將 Bean引用返回給調(diào)用者, Spring 繼續(xù)對這些 Bean 進(jìn)行后續(xù)的生命管理锯梁;
  • 1.4.13.對于 scope=“singleton”的 Bean,當(dāng)容器關(guān)閉時焰情,將觸發(fā) Spring 對 Bean 的后續(xù)生命周期的管理工作陌凳,首先如果 Bean 實(shí)現(xiàn)了 DisposableBean 接口,則將調(diào)用接口的afterPropertiesSet()方法内舟,可以在此編寫釋放資源合敦、記錄日志等操作;
  • 1.4.14.對于 scope=“singleton”的 Bean验游,如果通過<bean>的 destroy-method 屬性指定了 Bean 的銷毀方法充岛, Spring 將執(zhí)行 Bean 的這個方法,完成 Bean 資源的釋放等操作耕蝉。

可以將這些方法大致劃分為三類:

  • Bean 自身的方法:如調(diào)用 Bean 構(gòu)造函數(shù)實(shí)例化 Bean垒在,調(diào)用 Setter 設(shè)置 Bean 的屬性值以及通過<bean>的 init-method 和 destroy-method 所指定的方法;

  • Bean 級生命周期接口方法:如 BeanNameAware、 BeanFactoryAware谈为、 InitializingBean 和 DisposableBean旅挤,這些接口方法由 Bean 類直接實(shí)現(xiàn)伞鲫;

  • 容器級生命周期接口方法:在上圖中帶“★” 的步驟是由 InstantiationAwareBean PostProcessor 和 BeanPostProcessor 這兩個接口實(shí)現(xiàn)粘茄,一般稱它們的實(shí)現(xiàn)類為“ 后處理器” 。 后處理器接口一般不由 Bean 本身實(shí)現(xiàn)秕脓,它們獨(dú)立于 Bean嘹朗,實(shí)現(xiàn)類以容器附加裝置的形式注冊到 Spring 容器中并通過接口反射為 Spring 容器預(yù)先識別。當(dāng)Spring 容器創(chuàng)建任何 Bean 的時候,這些后處理器都會發(fā)生作用,所以這些后處理器的影響是全局性的。當(dāng)然甫何,用戶可以通過合理地編寫后處理器遇伞,讓其僅對感興趣Bean 進(jìn)行加工處理渐排。

1.5 ApplicationContext 與 BeanFactory 區(qū)別

  • BeanFactory:是Spring里面最低層的接口次乓,提供了最簡單的容器的功能杏慰,只提供了實(shí)例化對象和拿對象的功能缘滥;

  • ApplicationContext:應(yīng)用上下文,繼承BeanFactory接口,它是Spring的一各更高級的容器,提供了更多的有用的功能搪柑;

    1. 國際化(MessageSource)
    2. 訪問資源,如URL和文件(ResourceLoader)
    3. 載入多個(有繼承關(guān)系)上下文 ,使得每一個上下文都專注于一個特定的層次舱权,比如應(yīng)用的web層
    4. 消息發(fā)送仑嗅、響應(yīng)機(jī)制(ApplicationEventPublisher)
    5. AOP(攔截器)

同時ApplicationContext會利用 Java 反射機(jī)制自動識別出配置文件中定義的 BeanPostProcessor、 InstantiationAwareBeanPostProcessor 和 BeanFactoryPostProcessor羡亩,并自動將它們注冊到應(yīng)用上下文中速侈;
而BeanFactory 需要在代碼中通過手工調(diào)用 addBeanPostProcessor()方法進(jìn)行注冊。
這也是為什么在應(yīng)用開發(fā)時乾蛤,我們普遍使用 ApplicationContext 而很少使用 BeanFactory 的原因之一每界。

1.6 Spring的bean的存儲和管理機(jī)制

1、讀取config.xml文件的bean標(biāo)簽放入數(shù)組家卖,讀取內(nèi)容包含的id和class眨层。
2、循環(huán)數(shù)組并根據(jù)class路徑利用反射機(jī)制實(shí)例化Bean(實(shí)例化bean的過程就是上面)上荡,并放入Map(spring容器中的Bean緩存池)趴樱。
3、根據(jù)傳入的BeanId獲取Map中對應(yīng)的bean實(shí)例酪捡。

1.7 Spring bean獲取方式

從上面我們知道bean是存儲在hashMap中的叁征,其中key是beanId,vlaue是bean實(shí)例逛薇;

bean獲取方式其實(shí)就是從應(yīng)用上下文ApplicationContext的HashMap中根據(jù)key獲取value的過程捺疼。
方式一:Object getBean(String name)
方式二:<T> T getBean(String name, Class<T> requiredType)
方式一和方式二的區(qū)別只是方式二自動做了類型轉(zhuǎn)換。

1.8 ApplicationContext 獲取方式

方式一:讀取xml文件獲取ApplicationContext對象
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");

方式二:通過Spring提供的工具類獲取ApplicationContext對象
ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);

方式三:新建一個springUtils工具類永罚,且實(shí)現(xiàn)ApplicationContextAware接口
上面bean實(shí)例化時的第五步啤呼,如果bean實(shí)現(xiàn)了ApplicationContextAware接口卧秘,它的setApplicationContext()方法將被調(diào)用,將應(yīng)用上下文的引用傳入到bean中官扣;
通過這種方式可以把ApplicationContext傳入到springUtils中翅敌,然后再springUtils中就可以使用applicationContext.getBean()來獲取bean了

方式三是最推薦使用的

1.9 spring懶加載:

Spring默認(rèn)會在容器初始化的過程中,解析xml醇锚,并將單例的bean創(chuàng)建并保存到map中哼御,這樣的機(jī)制在bean比較少時問題不大,但一旦bean非常多時焊唬,spring需要在啟動的過程中花費(fèi)大量的時間來創(chuàng)建bean 花費(fèi)大量的空間存儲bean恋昼,但這些bean可能很久都用不上,這種在啟動時在時間和空間上的浪費(fèi)顯得非常的不值得赶促。
所以Spring提供了懶加載機(jī)制液肌。所謂的懶加載機(jī)制就是可以規(guī)定指定的bean不在啟動時立即創(chuàng)建,而是在后續(xù)第一次用到時才創(chuàng)建鸥滨,從而減輕在啟動過程中對時間和內(nèi)存的消耗嗦哆。

1.10 spring bean 注冊到 IOC容器的過程

  • 1、讀取bean配置信息(通過xml中<bean> 婿滓,或者通過注解@Autowrite @Configuration)老速,根據(jù)配置信息,在容器內(nèi)部建立Bean定義注冊表凸主;
  • 2橘券、根據(jù)bean注冊表實(shí)例化bean;
  • 3卿吐、將bean實(shí)例化并將其放入hashMap旁舰;
  • 4、獲取并使用bean

1.11 spring 循環(huán)依賴

spring 常用的注入方式有三種:構(gòu)造方法注入嗡官,setter注入箭窜,基于注解的注入。

所謂循環(huán)依賴衍腥,當(dāng)我們注入一個對象A時磺樱,需要注入對象A中標(biāo)記了某些注解的屬性,這些屬性也就是對象A的依賴婆咸,把對象A中的依賴都初始化完成竹捉,對象A才算是創(chuàng)建成功。那么擅耽,如果對象A中有個屬性是對象B,而且對象B中有個屬性是對象A物遇,那么對象A和對象B就算是循環(huán)依賴乖仇,如果不加處理憾儒,就會出現(xiàn):創(chuàng)建對象A-->處理A的依賴B-->創(chuàng)建對象B-->處理B的對象A-->創(chuàng)建對象A,這樣無限的循環(huán)下去乃沙,我們開發(fā)過程中有時也會遇到這種問題起趾,那么spring框架本身是怎么解決這個問題的呢?

從上面bean的生命周期中警儒,我們發(fā)現(xiàn)bean實(shí)例化(構(gòu)造器)和setter設(shè)置屬性并不是同時發(fā)生的训裆,這個其實(shí)就是解決循環(huán)依賴的依據(jù)。

當(dāng)我們初始化一個Bean時蜀铲,先調(diào)用Bean的構(gòu)造方法边琉,這個對象就在內(nèi)存中存在了(對象里面的依賴還沒有被注入),然后把這個對象保存下來记劝,當(dāng)循環(huán)依賴產(chǎn)生時变姨,直接拿到之前保存的對象,于是循環(huán)依賴就被終止了厌丑,依賴注入也就順利完成了定欧。

image.png
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//先存singletonObjects中獲取bean,
        Object singletonObject = this.singletonObjects.get(beanName);
//如果bean不存在怒竿,并且bean正在創(chuàng)建中
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
//從earlySingletonObjects中獲取
                singletonObject = this.earlySingletonObjects.get(beanName);
//如果earlySingletonObjects不存在(allowEarlyReference默認(rèn)為true)
                if (singletonObject == null && allowEarlyReference) {
//獲取singletonFactories
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
//從singletonFactories中獲取bean
                        singletonObject = singletonFactory.getObject();
//添加到earlySingletonObjects
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }
  • singletonObjects:緩存key = beanName, value = bean砍鸠;這里的bean是已經(jīng)創(chuàng)建完成的,該bean經(jīng)歷過實(shí)例化->屬性填充->初始化以及各類的后置處理耕驰。因此爷辱,一旦需要獲取bean時,我們第一時間就會尋找一級緩存

  • earlySingletonObjects:緩存key = beanName, value = bean耍属;這里跟一級緩存的區(qū)別在于托嚣,該緩存所獲取到的bean是提前曝光出來的,是還沒創(chuàng)建完成的厚骗。也就是說獲取到的bean只能確保已經(jīng)進(jìn)行了實(shí)例化示启,但是屬性填充跟初始化還沒有做完(AOP情況后續(xù)分析),因此該bean還沒創(chuàng)建完成领舰,僅僅能作為指針提前曝光夫嗓,被其他bean所引用

  • singletonFactories:該緩存key = beanName, value = beanFactory;在bean實(shí)例化完之后冲秽,屬性填充以及初始化之前舍咖,如果允許提前曝光,spring會將實(shí)例化后的bean提前曝光锉桑,也就是把該bean轉(zhuǎn)換成beanFactory并加入到三級緩存排霉。在需要引用提前曝光對象時再通過singletonFactory.getObject()獲取。

在整個getbean過程中民轴,singletonObjects攻柠、earlySingletonObjects球订、singletonFactories中對象變化如下

    1. 開始初始化對象A
      singletonFactories:
      earlySingletonObjects:
      singletonObjects:
    1. 調(diào)用A的構(gòu)造器實(shí)例化A,并把A放入singletonFactories
      singletonFactories:A
      earlySingletonObjects:
      singletonObjects:
    1. 開始注入A的依賴瑰钮,發(fā)現(xiàn)A依賴對象B之后冒滩,初始化對象B(同樣是調(diào)用B的構(gòu)造器實(shí)例化B,并把B放入singletonFactories)
      singletonFactories:A,B
      earlySingletonObjects:
      singletonObjects:
    1. 開始注入B的依賴浪谴,發(fā)現(xiàn)B依賴對象A开睡,開始初始化對象A,發(fā)現(xiàn)A在singletonFactories里有苟耻,則直接獲取A篇恒,把A放入earlySingletonObjects(提前曝光),把A從singletonFactories刪除
      singletonFactories:B
      earlySingletonObjects:A
      singletonObjects:
    1. 對象B的依賴注入完成之后梁呈,對象B創(chuàng)建完成婚度,把B放入singletonObjects,并且把B從earlySingletonObjects和singletonFactories中刪除
      singletonFactories:
      earlySingletonObjects:A
      singletonObjects:B
    1. 繼續(xù)A的初始化官卡,把對象B注入給A蝗茁,繼續(xù)注入A的其他依賴,直到A注入完成
      singletonFactories:
      earlySingletonObjects:A
      singletonObjects:B
    1. 對象A創(chuàng)建完成寻咒,把A放入singletonObjects哮翘,并把A從earlySingletonObjects和singletonFactories中刪除
      singletonFactories:
      earlySingletonObjects:
      singletonObjects:A,B
    1. 循環(huán)依賴處理結(jié)束,A和B都初始化和注入完成
      singletonFactories:
      earlySingletonObjects:
      singletonObjects:A,B

解決辦法:如果項目中出現(xiàn)了循環(huán)依賴毛秘,則使用setter注入替代構(gòu)造器注入饭寺。

2、AOP

2.1 概念

AOP的全稱是Aspect Orient Programming叫挟,即面向切面編程艰匙,擴(kuò)展功能不通過修改源代碼實(shí)現(xiàn)。

2.2實(shí)現(xiàn)方式

  • 2.2.1 JDK 動態(tài)代理(必須有接口)
    通過java.lang.reflect.Proxy類實(shí)現(xiàn)抹恳。
    動態(tài)代理就是為了解決靜態(tài)代理不靈活的缺陷而產(chǎn)生的员凝。靜態(tài)代理是固定的,一旦確定了代碼奋献,如果委托類新增一個方法健霹,而這個方法又需要增強(qiáng),那么就必須在代理類里重寫一個帶增強(qiáng)的方法瓶蚂。而動態(tài)代理可以靈活替換代理方法糖埋,動態(tài)就是體現(xiàn)在這里。同時窃这,靜態(tài)代理每個方法都需要單獨(dú)寫一個代理類瞳别,而動態(tài)代理一個接口只實(shí)現(xiàn)一個動態(tài)代理類即可。

設(shè)計模式中,有一種

  • 2.2.2 實(shí)現(xiàn)
Moveable move = (Moveable) Proxy.newProxyInstance(Car.class.getClassLoader(), Car.class.getInterfaces(), new LogHandler(new Car()));

使用JDK的動態(tài)代理去生成代理只需要一行代碼祟敛,傳入的參數(shù)中其實(shí)就倆倍奢,一是被代理類的類對象,二是自定義的增強(qiáng)處理代碼垒棋。
從上面的例子中可以看出,動態(tài)代理除了接受Car類型的目標(biāo)對象痪宰,還可以接受任何其他類型的對象叼架;也不管目標(biāo)對象實(shí)現(xiàn)的接口有多少方法,都可以被代理衣撬。


public class LogHandler implements InvocationHandler{ 
 
 private Object target; 
 
 public LogHandler(Object object){
   super();
   this.target = object;
 }
 
 //增強(qiáng)處理
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
   Object o = method.invoke(target,args);
   return o;
 }
}

image.png
  • 2.2.2 cglib 動態(tài)代理(不需要類繼承任何接口乖订,字節(jié)碼技術(shù))
public class Plane {

    public void fly(long ms) {
        System.out.println("plane is flying!");
        try {
            Thread.sleep(ms);
        } catch (Exception e) {

        }
    }
}

public class CglibProxy implements MethodInterceptor {
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        //1. 實(shí)例化工具類
        Enhancer en = new Enhancer();
        //2. 設(shè)置父類對象
        en.setSuperclass(this.target.getClass());
        //3. 設(shè)置回調(diào)函數(shù)
        en.setCallback(this);
        //4. 創(chuàng)建子類,也就是代理對象
        return en.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoke ");
        long begin = System.currentTimeMillis();

        //執(zhí)行目標(biāo)對象的方法
        Object returnValue = method.invoke(target, objects);

        long end = System.currentTimeMillis();
        System.out.println("after invoke elpased " + (end - begin));

        return returnValue;
    }

}

public static void main() {
    CglibProxy cglibProxy = new CglibProxy(new Plane()); 
    Plane plane = (Plane) cglibProxy.getProxyInstance();             
    plane.fly(150);
}

2.4使用場景:

    1. Logging 日志
    1. Authentication 權(quán)限
    1. Transactions 事務(wù)
    1. Context passing 內(nèi)容傳遞
    1. Error handling 錯誤處理
    1. Lazy loading 懶加載
    1. Debugging 調(diào)試
    1. logging具练,tracing乍构,profiling and monitoring 記錄跟蹤 優(yōu)化 校準(zhǔn)
    1. Performance optimization 性能優(yōu)化
    1. Persistence 持久化
    1. Resource pooling 資源池
    1. Synchronization 同步
    1. Caching 緩存

2.5 在Spring的AOP編程中

如果加入容器的目標(biāo)對象有實(shí)現(xiàn)接口,就使用JDK代理
如果目標(biāo)對象沒有實(shí)現(xiàn)接口扛点,就使用Cglib代理哥遮。

3、反射:

反射是Java的特征之一陵究,是一種間接操作目標(biāo)對象的機(jī)制眠饮,核心是JVM在運(yùn)行的時候才動態(tài)加載類,并且對于任意一個類铜邮,都能夠知道這個類的所有屬性和方法仪召,調(diào)用方法/訪問屬性,不需要提前在編譯期知道運(yùn)行的對象是誰松蒜,他允許運(yùn)行中的Java程序獲取類的信息扔茅,并且可以操作類或?qū)ο髢?nèi)部屬性

程序中對象的類型一般都是在編譯期就確定下來的秸苗,而當(dāng)我們的程序在運(yùn)行時召娜,可能需要動態(tài)的加載一些類,這些類因為之前用不到难述,所以沒有加載到j(luò)vm萤晴,這時,使用Java反射機(jī)制可以在運(yùn)行期動態(tài)的創(chuàng)建對象并調(diào)用其屬性胁后,它是在運(yùn)行時根據(jù)需要才加載店读。

3.1 new和反射創(chuàng)建有什么區(qū)別

new:靜態(tài)編譯,在編譯期就將模塊編譯進(jìn)來攀芯,執(zhí)行該字節(jié)碼文件屯断,所有的模塊都被加載;
反射:動態(tài)編譯,編譯期沒有加載殖演,等到模塊被調(diào)用時才加載氧秘;

3.2 反射的作用

  • 在運(yùn)行時判斷任意一個對象所屬的類;
  • 在運(yùn)行時構(gòu)造任意一個類的對象趴久;
  • 在運(yùn)行時判斷任意一個類所具有的成員變量和方法丸相;
  • 在運(yùn)行時調(diào)用任意一個對象的方法;

3.3 反射的實(shí)現(xiàn)

要使用一個類彼棍,就要先把它加載到虛擬機(jī)中灭忠,生成一個Class對象。這個class對象就保存了這個類的一切信息座硕。

反射機(jī)制的實(shí)現(xiàn)弛作,就是獲取這個Class對象,通過Class對象去訪問類华匾、對象的元數(shù)據(jù)以及運(yùn)行時的數(shù)據(jù)映琳。

//通過反射機(jī)制創(chuàng)建class對象
class1 = Class.forName(className);
//在運(yùn)行時,通過創(chuàng)建的class對象蜘拉,獲取自己的父類信息
Class<?> parentClass = class1.getSuperclass();
//通過反射機(jī)制創(chuàng)建一個類的對象
Classname 對象=class1.newInstance(參數(shù));
//取得本類已聲明的所有字段萨西,包括私有的、保護(hù)的
Field[] field = class1.getDeclaredFields();
//返回一個 Method 對象旭旭,它反映此 Class 對象所表示的類或接口的指定公共成員方法原杂。
Method method = clazz.getMethod(方法名,參數(shù)類型);
//調(diào)用具體某個實(shí)例對象的這個公有方法
method.invoke(實(shí)例對象您机,參數(shù)值);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末穿肄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子际看,更是在濱河造成了極大的恐慌咸产,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仲闽,死亡現(xiàn)場離奇詭異脑溢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赖欣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門屑彻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顶吮,你說我怎么就攤上這事社牲。” “怎么了悴了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵搏恤,是天一觀的道長违寿。 經(jīng)常有香客問我,道長熟空,這世上最難降的妖魔是什么藤巢? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮息罗,結(jié)果婚禮上掂咒,老公的妹妹穿的比我還像新娘。我一直安慰自己迈喉,他們只是感情好俏扩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著弊添,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捌木。 梳的紋絲不亂的頭發(fā)上油坝,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音刨裆,去河邊找鬼澈圈。 笑死,一個胖子當(dāng)著我的面吹牛帆啃,可吹牛的內(nèi)容都是我干的瞬女。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼努潘,長吁一口氣:“原來是場噩夢啊……” “哼诽偷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疯坤,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤报慕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后压怠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眠冈,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年菌瘫,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜗顽。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡雨让,死狀恐怖雇盖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情栖忠,我是刑警寧澤刊懈,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布这弧,位于F島的核電站,受9級特大地震影響虚汛,放射性物質(zhì)發(fā)生泄漏匾浪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一卷哩、第九天 我趴在偏房一處隱蔽的房頂上張望蛋辈。 院中可真熱鬧,春花似錦将谊、人聲如沸冷溶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逞频。三九已至,卻和暖如春栋齿,著一層夾襖步出監(jiān)牢的瞬間苗胀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工瓦堵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留基协,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓菇用,卻偏偏與公主長得像澜驮,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惋鸥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容