1. 程式人生 > 其它 >Spring不同裝配方式,代理模式,aop

Spring不同裝配方式,代理模式,aop

使用註解開發

  1. bean

  2. 屬性如何注入

    //等價於
    //@Compoent 元件
    @Component
    public class User {
    //相當於:

     public String name;
     @Value("cch2")
     public void setName(String name) {
         this.name = name;
     }
    

    }

  3. 衍生註解

@Component有幾個衍生註解,我們在web開發中,會按照mvc三層架構分層

  • dao 【@Repository】
  • service【@Service】
  • controller【@Controller】

這四個註解功能都是一樣的,都是代表將某個類註冊到Spring中,裝配Bean

  1. 自動裝配

    • @Autowired:自動裝配,通過型別。名字
      如果Autowired不能唯一自動裝配屬性,則需要通過@Qualifier(value = "xxx")
    • @Nullable 欄位標記了這個註解,說明這個欄位可以為null;
    • @Resource: 自動裝配,通過名字。型別

作用域

@Component
@Scope("singleton")
public class User {
//相當於:<property name="name" value="cch2"/>

    public String name;
    @Value("cch2")
    public void setName(String name) {
        this.name = name;
    }
}

小結

xml與註解:

  • xml更加萬能,適用於任何場合 。維護簡單方便
  • 註解:不是自己的類使用不了,維護相對複雜

xml與註解最佳實踐:

  • xml用來管理bean;

  • 註解只負責完成屬性的注入;

  • 我們在使用的過程中,只需要注意一個問題:必須讓註解實效,就需要開啟註解的支援

      <context:component-scan base-package="com.king"/>
      <context:annotation-config/>
    

使用java的方式配置Spring

實體類

//這裡這個註解的意思,就是說明這個類被Spring接管了,註冊到了容器中
@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }
    @Value("xsb")//屬性注入值
    public void setName(String name) {
        this.name = name;
    }

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

配置檔案

//這個也會被Spring容器託管,註冊到容器中,他本來就是@Component,
// @Configuration 代表這是一個配置類,就和我們之前看到的bean.xml

@Configuration
@ComponentScan("com.kua.pojo")
@Import(MyConfig2.class)
public class MyConfig {

    //註冊一個bean,就相當於我們之前寫的一個bean標籤
    //這個方法的名字,就相當於標籤中的id屬性
    //這個方法的返回值,就相當於bean標籤中的class屬性

    @Bean
    public User getUser(){
        return new User();//就是返回要注入到bean的物件
    }
}

測試類

public class MyTest {
    public static void main(String[] args) {
        //如果完全使用了配置類的方式去做,我們就只能通過ApplicationConfig 上下文來獲取容器,通過配置類的class物件載入
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = context.getBean("getUser", User.class);
        System.out.println(user.getName());
    }
}

這種純java的配置方式,在SpringBoot中隨處可見

代理模式

SpringAOP的底層就是代理模式

代理模式的分類:

  1. 靜態代理

角色分析:

  • 抽象角色:一般會使用介面或者抽象類來決定
  • 真實角色:被代理的角色
  • 代理角色:代理真實物件,代理真實角色後,我們一般會 做一些附屬操作
  • 客戶:訪問代理物件的人

程式碼步驟:

  1. 介面
    public interface Rent {
    public void rent();
    }

  2. 真實角色
    //房東
    public class Host implements Rent{

        public void rent() {
            System.out.println("房東要出租房子");
        }
    }
    
  3. 代理角色
    public class Proxy implements Rent{
    private Host host;

        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        public void rent() {
            host.rent();
            seeHouse();
            fare();
            ht();
            System.out.println("中介代你向房東租房");
        }
    
        //看房
        public void seeHouse(){
            System.out.println("中介帶你看房");
        }
        //收中介費
        public void fare(){
            System.out.println("收中介費");
        }
        //籤租賃合同
        public void ht(){
            System.out.println("籤租賃合同");
        }
    }
    
  4. 客戶端訪問代理角色
    public class Client {
    public static void main(String[] args) {
    //房東要出租房子
    Host host = new Host();
    //代理,中介棒房東出租房子,但是呢。同時代理角色一般有一些附屬操作
    Proxy proxy = new Proxy(host);
    //你不用面對房東,直接找中介租房即可
    proxy.rent();
    }
    }

代理模式的好處:

  • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務。
  • 公共業務就交給代理物件去做,實現業務的分工。
  • 公共業務發生擴充套件的時候,方便集中管理。

缺點:

  • 一個真實角色就會產生一個代理角色;程式碼量會翻倍,導致開發效率變低

動態代理

  • 動態代理和靜態代理角色一樣
  • 動態代理的代理類是動態生成的,不是我們直接寫好的
  • 動態代理分成兩大類:基於介面的動態代理,基於類的動態代理
    • 基於介面---JDK動態代理
    • 基於類:cglib
    • 位元組碼檔案實現:javassist

需要了解兩個類:Proxy:代理,InvocationHandler:呼叫處理程式

動態代理的好處:

  • 可以使真實角色的操作更加純粹,不用去關注一些公共的業務。
  • 公共業務就交給代理物件去做,實現業務的分工。
  • 公共業務發生擴充套件的時候,方便集中管理。
  • 一個動態代理類代理的是一個介面,一般對應的是一類業務。
  • 一個動態代理類可以代理多個類只要是實現了同一個介面即可。

使用spring實現aop

【重點】使用aop注入,需要匯入一個依賴包

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

方式一:使用Spring的API介面實現

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--註冊bean-->
    <bean id="userService" class="com.xxx.service.UserServiceImpl"/>
    <bean id="log" class="com.xxx.log.Log"/>
    <bean id="afterLog" class="com.xxx.log.AfterLog"/>
<!--方式一:使用原生Spring API介面-->
<!-- 配置aop:需要匯入aop的約束-->
    <aop:config>
        <!--切入點:expression:表示式。execution(要執行的位置 * * * * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.xxx.service.UserServiceImpl.*(..))"/>

        <!--執行環繞增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

方式二:自定義AOP實現【切面定義】

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--註冊bean-->
    <bean id="userService" class="com.xxx.service.UserServiceImpl"/>
    <bean id="log" class="com.xxx.log.Log"/>
    <bean id="afterLog" class="com.xxx.log.AfterLog"/>
   
    <!--方式二:自定義類-->
    <bean id="diy" class="com.xxx.diy.DiyPointCut"/>

    <aop:config>
        <!-- 自定義切面,ref要引用的類 -->
        <aop:aspect ref="diy">
            <!--切入點-->
            <aop:pointcut id="point" expression="execution(* com.xxx.service.UserServiceImpl.*(..))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>
</beans>

方式三:使用註解方式實現AOP

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--註冊bean-->
    <bean id="userService" class="com.xxx.service.UserServiceImpl"/>
    <bean id="log" class="com.xxx.log.Log"/>
    <bean id="afterLog" class="com.xxx.log.AfterLog"/>
 
<!-- 方式三:使用註解實現AOP-->
    <bean id="annotationPointCut" class="com.xxx.diy.AnnotationPointCut"/>
<!--開啟註解支援  JDK(預設 proxy-target-class="false") cglib(proxy-target-class="false)-->
    <aop:aspectj-autoproxy/>
</beans>