Spring基礎學習

@component是用來創建對象的。默認是創建單例對象。

   屬性: value , 表示<bean>對象的 id,也就是對象的名稱。

   位置:在類的定義上面。  基本上所有的可以給類 使用的註解 都是寫在類的上面的。

@component(value=所要創建的對象的名稱)  因爲寫在了類的上面就不用再像<bean>標籤一樣需要寫類的全地址了  等價於:

<bean id=所要創建的對象的名稱” class=類的全地址/>

我們使用註解來創建對象的前提是:我們需要一個掃描器來掃描我們的 這個有註解標示的類,當掃描到這個註解的時候,我們的spring容器就會根據我們的註解的中的value屬性和當前類所在的位置來 創建一個 我們所需要的對象。

 

和 @Component註解相同作用的爲:

@Repository:放在dao層的實現類上面,創建dao對象。

@Service:放在Service層實現類上面,創建service對象的。

@Controller:放在控制器類上面,創建控制器對象(servlet)。控制器不像我們的service和dao這兩個層,controller是沒有接口的。

 

 

package com.bjpowernode.domain;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;

 

 

//在註解裏面 value就相當於我們的標籤對象的的id屬性,相當於對象的名稱或者屬性的數值。

@Component(value="MyUser")

public class User {

@Value(value="張三")

private String name ;

@Value("18")

private int age ;

@Autowired    //這個默認爲byType ,按照類型進行匹配和賦值。

private School school;  

//spring容器會爲我們的school對象從容器中尋找一個和他類型相同的對象: mySchool,然後給他賦值。

@Autowired //比較類型

@Qualifier(value="teacher") //比較 名字是否爲 我們設置的 對象名 teacher

//上面兩個 註解 構成了我們的 byName規則。

private Teacher teacher ;

 

public String getName() {

return name;

}

 

public void setName(String name) {

this.name = name;

}

 

public int getAge() {

return age;

}

 

public void setAge(int age) {

this.age = age;

}

 

public School getSchool() {

return school;

}

 

public void setSchool(School school) {

this.school = school;

}

 

@Override

public String toString() {

return "User [name=" + name + ", age=" + age + ", school=" + school + ", teacher=" + teacher + "]";

}

 

}

 

我們給簡單數據類型的屬性賦值; @Value(value="張三")或者 @Value("張三") 

我們給 引用數據類型的屬性賦值,給應用數據類型賦值:我們使用自動注入的方法來給我們的  引用數據類型賦值。

我們使用註解的方式來 自動注入我們的 引用數據 類型的屬性。 自動注入有分爲兩類:byName和byType;

 

byType 規則所對應的註解爲:

  @AutoWried   在一個引用數據類型的屬性上面使用這個 註解 ,就表名這個引用數據類型的屬性 是由我們的 spring容器 按照byType的規則然後從容器中尋找 與 這個引用數據類型的屬性的 類型相同的 <bean>對象(<bean>對象我是是指的 存放在我們的spring容器的當中的對象)

 

byName的引用數據類型的屬性的自動注入方式:

使用的註解有: 我們需要 @Qualitier 和 @Autowried 這兩個 註解配合在一起使用纔可以。

我們的@Autowried 這個註解 告訴我們的 組件掃描器  在spring容器中進行查找的時候,應該找 相同數據類型的 對象。我們的@Qualitier(value=對象名稱)是告訴我們的掃描器 查找對象的時候 需要 找名字相同的,名字爲value的值。

 

 

我們的 @Autowired 註解中有一個屬性,這個屬性爲 required。

Required這個屬性是一個boolean 類型的,有兩個值:true和false;

True:設置爲true,產生的效果爲: 當引用類型賦值失敗了,程序會報錯,而且程序會中止執行。

False: 引用類型屬性如果賦值失敗了,程序不會報錯,也不會終止,正常的執行,但是我們的引用數據類型的屬性的值爲 null 。

組件掃描器 是用來掃描我們包中的類中的 註解的,然後 按照我們 註解提供的信息來創建一個 我們 想要的對象。

 

我們一個組件掃描器(用來掃描 當前包下和所有的子包 中 所含有的 所有的類中的 註解),我們的一個掃描器一次只能掃描一個包,掃面這個包下面的所有的子包和自身包中的類的註解。

 

我們掃描器 一次性不能掃描兩個 沒有父子關係的 而是兄弟關係或者是同級關係的包。

 

我們有三種方法來給 多個包 聲明 多個 組件掃面器:

第一種是: 每一個包 對應一個  

<context:component-scan base-package="com.bjpowernode" />

第二種:我們只寫一個標籤,但是我們在base-package中同時寫多個包的全地址,地址與地址之間使用;或者,分割。

<context:component-scan base-package="com.bjpowernodo.dao;com.bjpowernode.domain;com.bjpowernode.service" />

第三種是: 我們找到 我們 需要爲那幾個包聲明組件掃描器,然後找出來這幾個包的共同的父包,然後在 base-package上面寫這個父包的 全地址。

補充知識點:

(1)使用 @Resource這個註解來給我們的引用數據類型賦值。

(2)使用這個註解來給我們的 引用數據類型的屬性賦值的時候,不需要提供set方法,直接將這個@Resource註解寫在我們引用數據類型屬性的上面就可以了。

(3)@Resource 這個註解是按照什麼標準和規則進行 對 引用數據類型屬性進行賦值的?

我們利用註解的方式來對引用數據類型賦值無非是遵守兩個規則:一個是 byName 一個是我們的 byByte。

(4)但是 @Resource 註解 先按照 byName的注入規則進行賦值,如果byName的規則不能成功,那麼@Resource這個註解就會再使用byType這種注入的規則。

使用byName規則時候,需要比較名字和類型,可能名字不相同,但是類型相同,然後byName規則賦值失敗,然後使用byType規則賦值的時候,因爲類型相同,所以byType規則賦值成功。

  1. 我們 如何 讓 @Resource 這個註解 只按照 byName 這種 賦值規則來 進行賦值呢?不讓它在 byName 賦值失敗之後 又使用 byType這種規則賦值,因爲這樣的話可能 在ByName賦值失敗之後 程序會不報錯的,所以說 我們要讓 @Resource這個註解只按照byName這一種賦值方式進行賦值,當byName賦值失敗之後就給我們 報錯 ,我們看到錯誤信息。

方法就是:

@Resource(name=”byName規則用來比較的對象名稱”)

給我們的 @Resource 這個註解增加一個name 屬性,然後給這個name屬性賦值,賦的值爲:需要比較的對象名,這樣我們的@Resource只會使用byName規則進行賦值。

使用 @Configuration 這個註解的類,這個類就當做了xml配置文件了。

總結一下: 

  1. 我們使用一個實體類來模擬我們的xml配置

文件。然後 我們使用實體類中的方法類模擬我們

的xml配置文件中的<bean>標籤。

  1. 我們如何讓spring知道 我們類就是原先的xml配置文件呢?

  在我們的類的上面 使用 @Configruation ,這個@Configruation這個註解就是用來說明我們這個類就是一個配置類。

  1. 我們如何讓spring知道我們的類中的方法就是原來xml文件中的<bean>標籤呢?

在我們的而每個方法上面 使用 @Bean 這個註解,這個@Bean這個註解就是用來說明我們的這個方法就相當於原來的 <bean>標籤的,使用方法模擬<bean>標籤創建出來的對象的默認名字爲 方法名。 如果我們需要自定義對象的名稱,那麼我們就給@Bean這個註解添加一個name屬性,這個屬性的值就是我們自定義對象的名稱。

一定要記住上面用到的兩個註解:分別爲: @Configruation  和 @Bean 。

 

 

回顧一下動態代理:

1)jdk的動態代理:要求目標類必須實現接口,對接口中的方法能增強功能。

     使用的類和接口列表:

     ①:InvocationHandler接口:實現接口中的invoke()方法, 在方法中實現功能增強,例如事務處理

     ②:Method類: 主要作用是調用執行目標方法 method.invoke();

     ③:Proxy類:proxy.newProxyInstance();靜態方法,創建代理對象。

 

  2)cglib動態代理, cglib是一個工具庫,實現動態代理的功能,修改內存中的java對象,增加功能。

    cglib實現動態代理的原理:繼承, 通過繼承目標類,創建一個子類,在子類中重寫方法的內容,實現

    功能的修改,增強。 這個子類就是一個代理類。

    cglib使用繼承,要求目標類不能是final的,要增強功能的方法也不能是final的。

    cglib在很多的框架中使用。因爲他對目標類的要求低。

 

cglib動態代理 實現動態代理的方法: 本質就是 繼承的原理,讓子類繼承父類中的方法,然後在子類中重寫父類中的方法,重寫的時候就可以對父類的方法進行修改增強擴展了,這一點和我們 jdk動態代理的作用就是增強和擴展 業務層方法的 功能 是一樣的。


package com.bjpowernode.ba01;

 

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

 

/**

 * @Aspect:表示當前類是切面類。

 * 切面類作用是給目標類增強功能的。

 *   位置:在類定義的上面

 *

 */

@Aspect

public class MyAspect {

/**

 * 前置通知:@Before

 *    屬性:value ,表示切入點表達式

 *    位置:在方法的上面

 *    

 * @Before:表示切面的執行時間

 * value:表示切面執行的位置。在哪裏加入切面的功能。

 *

 * 特點:

 * 1.在目標方法之前先執行的。

 * 2.不會改變目標方法的執行結果

 * 3.不會影響目標方法的執行

 */

/*@Before(value="execution(* com.bjpowernode.ba01.SomeServiceImpl.doSome(..))")

public void myBefore(){

//切面的代碼,要增強的功能,寫在這裏

System.out.println("前置通知:在目標方法之前,加入日誌的功能(切面)");

}*/

 

/**

 * 參數:

 * JoinPoint:表示切入點表達式中的方法。

 */

/*@Before(value="execution(* com.bjpowernode.ba01.SomeServiceImpl.do*(..))")

public void myBefore(JoinPoint jp){

//獲取執行的方法名

String methodName = jp.getSignature().getName();

//獲取參數個數

Object args []  = jp.getArgs();//表示方法的參數集合

for(Object arg:args){

System.out.println(arg);

}

 

//切面的代碼,要增強的功能,寫在這裏

System.out.println("前置通知:在目標方法之前,加入日誌的功能(切面)當前正在執行的方法名:"+methodName+",方法的參數個數:"+args.length);

}*/

 

@Before(value="execution(* *..SomeServiceImpl.*(..))")

public void myBefore(JoinPoint jp){

//獲取執行的方法名

String methodName = jp.getSignature().getName();

//獲取參數個數

Object args []  = jp.getArgs();//表示方法的參數集合

for(Object arg:args){

System.out.println(arg);

}

 

//切面的代碼,要增強的功能,寫在這裏

System.out.println("前置通知:在目標方法之前,加入日誌的功能(切面)當前正在執行的方法名:"+methodName+",方法的參數個數:"+args.length);

}

}

 

我的理解:

package com.bjpowernode.proxy;

 

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.springframework.stereotype.Component;

@Component(value="myProxy")

@Aspect //這個註解的意思是說明我們的這個類 是  一個 切面類,切面類是在我們的AspectJ這個框架裏面的。

public class MyProxy {//切面類中的切面就是我們類中的方法。

@Before(value="execution(* com.bjpowernode.service.UserServiceImpl.addUser(..))") //before註解的意思是  我們這個切面 切入的時間,是在 目標方法之前還是目標方法之後,我們的這個before是 表示 在目標方法執行前 切入。

//上面的意思是: 位置在com.bjpowernode.dao.UserDaoOracleImpl類中的 任意返回值類型任意參數個數的insertUser方法。

//value代表的意思是:切入點位置,這個value的值有一個 切入點表達式,一般是:

//  value="execution(* com.bjpowernode.service.目標類.目標方法(..))" 其中..的意思是:任意個參數。

//如果..跟在包名的後面:說明是 包及其子包 。

// * 代表任意多個字符,..跟在包後面說明 是 本包及其子包  ..在包的前面 說明 本包和它的父包。 ..在參數裏面代表任意多個參數。

public void addAction(){//我們的這個增強目標類中目標方法的 切面 必須是 public void 的,因爲如果你 有返回值的話,到了我們的業務層目標方法中 又要處理你這個方法的返回值,這樣子我們的業務層方法又不能專心做業務了。

System.out.println("你被強化了!!!出去戰鬥吧!!!");

}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章