Spring-05 使用註解開發

zc發表於2021-03-03

Spring-05 使用註解開發

使用註解開發

1.專案準備

在spring4之後,想要使用註解形式,必須得要引入aop的包5

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.3.3</version>
        </dependency>

在配置檔案當中,還得要引入一個context約束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

</beans>

2.Bean實現

我們之前都是使用 bean 的標籤進行bean注入,但是實際開發中,我們一般都會使用註解!

1、配置掃描哪些包下的註解

<context:component-scan base-package="pojo"/>

2、在指定包下編寫類,增加註解

// 相當於配置檔案中 <bean id="user" class="當前註解的類"/>
@Component("user")
public class User {
    public String name = "zc";
}

3.測試

    @Test
    public void UserTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        User user = (User) applicationContext.getBean("user");
        System.out.println(user.name);
    }
1

3.屬性注入

3.1 不提供set方法

可以不提供set方法,直接在屬性名上新增@value(“xxx”)

@Component("user")
public class User {
    // 相當於配置檔案中 <property name="name" value="秦疆"/>
    @Value("zc")
    public String name;
}

測試結果成功

3.1 提供了set方法

如果提供了set方法,在set方法上新增@value(“xxx”)

@Component("user")
public class User {
    public String name;
    
    @Value("zc")
    public void setName(String name) {
        this.name = name;
    }
}

測試結果成功

4.衍生註解

我們這些註解,就是替代了在配置檔案當中配置步驟而已!更加的方便快捷!

@Component三個衍生註解

為了更好的進行分層,Spring可以使用其它三個註解,功能一樣,目前使用哪一個功能都一樣。

  • @Controller:web層
  • @Service:service層
  • @Repository:dao層

寫上這些註解,就相當於將這個類交給Spring管理裝配了!

作用域

@scope

  • singleton:預設的,Spring會採用單例模式建立這個物件。關閉工廠 ,所有的物件都會銷燬。
  • prototype:多例模式。關閉工廠 ,所有的物件不會銷燬。內部的垃圾回收機制會回收
@Component("user")
@Scope("prototype")
public class User {
    @Value("zc")
    public String name;
}

總結

XML與註解比較

  • XML可以適用任何場景 ,結構清晰,維護方便
  • 註解不是自己提供的類使用不了,開發簡單方便

xml與註解整合開發 :推薦最佳實踐

  • xml管理Bean
  • 註解完成屬性注入
  • 使用過程中, 可以不用掃描,掃描是為了類上的註解
<context:annotation-config/>  

作用:

  • 進行註解驅動註冊,從而使註解生效
  • 用於啟用那些已經在spring容器裡註冊過的bean上面的註解,也就是顯示的向Spring註冊
  • 如果不掃描包,就需要手動配置bean
  • 如果不加註解驅動,則注入的值為null

5.使用java的方式配置Spring

我們現在要完全不使用spring的xml配置,全權交給java來做。

5.1 實體類

@Controller
public class UserT {
        // 屬性的注入
        @Value("zcT")
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
}

5.2 配置類

@Configuration:本質上也是一個Controller,也會被spring託管,註冊到容器中

@Configuration:表示這是一個配置類,和之前的beans.xml的功能一樣的

@ComponentScan:表示元件的掃描

@import:匯入其他的配置類

@Bean:表示註冊一個bean

@Configuration
@ComponentScan("pojo")
public class MyConfig {
    // 方法的名字即是bean中的id
    // 方法的返回值就是bean中的class
    @Bean
    public UserT getUserT(){
        return new UserT();      // return就是返回要注入到bean中的物件
    }
}  

5.3 測試

    @Test
    public void UserTTest(){
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        UserT userT = (UserT) context.getBean("getUserT");
        System.out.println(userT.toString());
    }
2

代理模式

為什麼要學習代理模式,因為AOP的底層機制就是動態代理。

代理模式:

  • 靜態代理
  • 動態代理

1.靜態代理

角色分析

  • 抽象角色 : 一般使用介面或者抽象類來實現
  • 真實角色 : 被代理的角色
  • 代理角色 : 代理真實角色 ; 代理真實角色後 , 一般會做一些附屬的操作
  • 客戶 : 使用代理角色來進行一些操作

1.1 案例分析

1.1.1 介面類
public interface Rent {
    public void rent();
}
1.1.2 實體類
//房東
public class Host implements Rent{
    public void rent() {
        System.out.println("出租房子");
    }
}
//代理類
public class Proxy implements Rent{
    private Host host;
    public Proxy(){
    }
    public Proxy(Host host){
        this.host = host;
    }
    // 因為要幫房東租房子,所以代理也要實現租房子
    public void rent() {
        host.rent();
    }
    //看房
    public void seeHouse(){
        System.out.println("帶房客看房");
    }
    //收中介費
    public void fare(){
        System.out.println("收中介費");
    }
}
1.1.3 測試實體類
public class Client {
    public static void main(String[] args) {
        // 房東要租房
        Host host = new Host();
        // 中介幫房東
        Proxy proxy = new Proxy(host);
        // 去找中介
        proxy.rent();
    }
}

分析:在這個過程中,你直接接觸的就是代理類(Proxy),就如同現實生活中的樣子,你看不到房東,但是你依舊通過中介,租到了房東的房子,這就是所謂的代理模式。

靜態代理的好處:

  • 可以使得我們的真實角色更加純粹 . 不再去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實現了業務的分工 ,
  • 公共業務發生擴充套件時變得更加集中和方便 .

缺點 :

  • 類多了 , 多了代理類 , 工作量變大了 . 開發效率降低 .

我們在不改變原來的程式碼的情況下,實現了對原有功能的增強,這是AOP中最核心的思想。

2.動態代理

  • 動態代理的角色和靜態代理的一樣 .

  • 動態代理的代理類是動態生成的,靜態代理的代理類是我們提前寫好

  • 動態代理分為兩類 : 一類是基於介面動態代理 , 一類是基於類的動態代理

    • 基於介面的動態代理----JDK動態代理
    • 基於類的動態代理--cglib
    • 現在用的比較多的是 javasist 來生成動態代理
    • 我們這裡使用JDK的原生程式碼來實現

2.1 JDK的動態代理需要了解兩個類

核心 : InvocationHandler 和 Proxy

【InvocationHandler:呼叫處理程式】

Object invoke(Object proxy, 方法 method, Object[] args);
//引數
//proxy - 呼叫該方法的代理例項
//method -所述方法對應於呼叫代理例項上的介面方法的例項。方法物件的宣告類將是該方法宣告的介面,它可以是代理類繼承該方法的代理介面的超級介面。
//args -包含的方法呼叫傳遞代理例項的引數值的物件的陣列,或null如果介面方法沒有引數。原始型別的引數包含在適當的原始包裝器類的例項中,例如java.lang.Integer或java.lang.Boolean 。

【Proxy : 代理】

//生成代理類
public Object getProxy(){
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                  rent.getClass().getInterfaces(),this);
}

2.2 案例分析

2.2.1 介面類
//抽象角色:租房
public interface Rent {
   public void rent();
}
2.2.2 實體類
//房東
public class Host implements Rent{
    public void rent() {
        System.out.println("出租房子");
    }
}
2.2.3 代理類
public class ProxyInvocationHandler implements InvocationHandler {
    private Rent rent;
    public void setRent(Rent rent) {
        this.rent = rent;
    }
    //生成代理類,重點是第二個引數,獲取要代理的抽象角色!之前都是一個角色,現在可以代理一類角色
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                rent.getClass().getInterfaces(),this);
    }
    // proxy : 代理類 method : 代理類的呼叫處理程式的方法物件.
    // 處理代理例項上的方法呼叫並返回結果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable     {
        //核心:本質利用反射實現!
        Object result = method.invoke(rent, args);
        fare();
        return result;
    }
    //看房
    public void seeHouse(){
        System.out.println("帶房客看房");
    }
    //收中介費
    public void fare(){
        System.out.println("收中介費");
    }
}
2.2.4 測試實體類
public class Client {
    public static void main(String[] args) {
        //真實角色
        Host host = new Host();
        //代理例項的呼叫處理程式
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setRent(host); //將真實角色放置進去
        Rent proxy = (Rent)pih.getProxy(); //動態生成對應的代理類
        proxy.rent();
    }
}
1

一個動態代理 , 一般代理某一類業務 , 一個動態代理可以代理多個類,代理的是介面

2.3 動態代理的好處

靜態代理有的它都有,靜態代理沒有的,它也有!

  • 可以使得我們的真實角色更加純粹 . 不再去關注一些公共的事情 .
  • 公共的業務由代理來完成 . 實現了業務的分工 ,
  • 公共業務發生擴充套件時變得更加集中和方便 .
  • 一個動態代理 , 一般代理某一類業務
  • 一個動態代理可以代理多個類,代理的是介面!

個人部落格為:
MoYu's Github Blog
MoYu's Gitee Blog

相關文章