前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring-1.依赖注入(BI)和面向切面编程(AOP)

Spring-1.依赖注入(BI)和面向切面编程(AOP)

作者头像
悠扬前奏
发布2019-05-30 20:29:00
4790
发布2019-05-30 20:29:00
举报

1 依赖注入

通过依赖注入(Dependency Injection, DI),对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。

1.1 实现

对于如下类

代码语言:javascript
复制
package com.junzerg.spring_knight;

public class BraveKnight implements Knight {

    private Quest quest;

    public BraveKnight(Quest quest) {
        this.quest = quest;
    }

    public void embarkOnQuest() {
        quest.embark();
    }
}
  1. BraveKnight没有自己创建探险任务,而是在构造的时候把探险任务作为构造器参数传入。这是依赖注入的一种方式,构造器注入(constructor injection)。
  2. 传入的探险类型Quest,是所有的探险任务都必须实现的一个接口。
  3. BraveKnight没有与特定的Quest实现发生耦合,只要求探险任务实现了Quest接口。

可以看出: DI带来的最大的好处就是松耦合。如果一个对象只通过接口(而不是具体实现或者初始化过程)来表明依赖关系,那么这种依赖就能在对象本身毫不知情的情况下,用不同的具体实现进行替换。

1.2 注入

对于#1中的BraveKnight类。可以接受任意一种Quest的实现,例如如下类:

代码语言:javascript
复制
package com.junzerg.spring_knight;

import java.io.PrintStream;

public class SlayDragonQuest implements Quest {

    private PrintStream stream;

    public SlayDragonQuest(PrintStream stream) {
        this.stream = stream;
    }

    public void embark() {
        stream.println("Embarking on quest to slay the dragon!");
    }
}

创建了这个类之后,剩下的就是将这个类交给BraveKnight。这就是创建应用组件之间的写作的行为,被称为装配(wiring)。

1.3 装配

Spring支持两种装配的方式。

1.3.1 xml配置
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="knight" class="com.junzerg.spring_knight.BraveKnight">
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="com.junzerg.spring_knight.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}" />
    </bean>

</beans>

以上配置功能为:

  1. 将BraveKnight和SlayDragonQuest声明为Spring中的bean。
  2. 在构造BraveKnight bean的时候传入SlayDragonQuest bean的应用,作为构造器的参数。
  3. 在构造SlayDragonQuest bean的时候将System.out传入到构造器中。
1.3.2 Java描述配置
代码语言:javascript
复制
package com.junzerg.spring_knight.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.junzerg.spring_knight.BraveKnight;
import com.junzerg.spring_knight.Knight;
import com.junzerg.spring_knight.Quest;
import com.junzerg.spring_knight.SlayDragonQuest;

@Configuration
public class KnightConfig {
    
    @Bean
    public Knight knight() {
        return new BraveKnight(quest());
    }
    
    @Bean
    public Quest quest() {
        return new SlayDragonQuest(System.out);
    }
}

作用和用 xml配置的一样。

1.4 实现
1.4.1 xml配置的实现

对于xml配置的情况,使用ClassPathXmlApplicationContext(加载位于应用程序类路径下的一个或者多个XML配置文件)。

代码语言:javascript
复制
package com.junzerg.spring_knight;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class KnightMain {

    @Autowired
    Knight knight;

    public static void main(String[] args) throws Exception {
         ClassPathXmlApplicationContext context = new
         ClassPathXmlApplicationContext("META-INF/spring/knight.xml");
         Knight knight = context.getBean(Knight.class);
         knight.embarkOnQuest();
         context.close();
    }
}
1.4.2 Java配置的实现

对于Java配置的情况,使用AnnotationConfigApplicationContext。

代码语言:javascript
复制
package com.junzerg.spring_knight;

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

import com.junzerg.spring_knight.config.KnightConfig;

public class KnightMain {

    @Autowired
    Knight knight;

    public static void main(String[] args) throws Exception {

        AnnotationConfigApplicationContext content = new AnnotationConfigApplicationContext(KnightConfig.class);
        Knight knight = content.getBean(Knight.class);
        knight.embarkOnQuest();
    }
}
1.5 上下文中其他类和结果
1.5.1 上下文中其他类
  1. Knight
代码语言:javascript
复制
package com.junzerg.spring_knight;

public interface Knight {

    void embarkOnQuest();

}
  1. Quest
代码语言:javascript
复制
package com.junzerg.spring_knight;

public interface Quest {

    void embark();

}
1.5.2 运行结果:

Embarking on quest to slay the dragon!

1.5.3 Maven

我是在Maven中添加Spring依赖的,这一节只需要用到Spring的上下文(context)依赖,如下:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

2 面向切面编程(AOP)

通过面向切面编程(aspect-oriented programming, AOP),把遍布应用各处的功能分离出来形成可重用的组件。 AOP将横切关注点(跨越系统的多个组件,例如日子,事务管理,安全等)模块化,并以声明的方式将它们应用到需要影响的组件中去,这样能够使这些组件有更高的内聚性并且会更加关注自身的业务,不需要了解涉及系统服务带来的复杂性,从而保证了POJO的简单性。

2.1 AOP简单应用

对于#1中的骑士的事迹,用一个吟游诗人来记载。

代码语言:javascript
复制
package com.junzerg.spring_knight;

import java.io.PrintStream;

public class Minstrel {

    private PrintStream stream;

    public Minstrel(PrintStream stream) {
        this.stream = stream;
    }

    public void singBeforeQuest() {
        stream.println("Fa la la, the knight is so brave!");
    }

    public void singAfterQuest() {
        stream.println("Tee hee hee, the brave knight " + "did embark on a quest!");
    }

}

Minstrel类,在骑士执行每一个探险任务之前,singBeforeQuest被调用;在骑士完成探险任务之后,singAfterQuest()方法会被调用;这两种情况都通过PrintStream类来歌颂事迹,这个类是通过构造器来引入的。

**那么,在普通情况下,编写这个类之后,会在BraceKnight中使用这个类。但是利用AOP,可以在骑士类不访问吟游诗人类的情况下,让吟游诗人歌颂骑士的事迹。

这种技术是通过在Spring配置文件中将Minstrel声明为一个切面实现的。

minstrel.xml

代码语言:javascript
复制
<?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/aop 
      http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="knight" class="sia.knights.BraveKnight">
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="sia.knights.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}" />
    </bean>

    <bean id="minstrel" class="sia.knights.Minstrel">
        <constructor-arg value="#{T(System).out}" />
    </bean>

    <aop:config>
        <aop:aspect ref="minstrel">
            <aop:pointcut id="embark" expression="execution(* *.embarkOnQuest(..))" />

            <aop:before pointcut-ref="embark" method="singBeforeQuest" />

            <aop:after pointcut-ref="embark" method="singAfterQuest" />
        </aop:aspect>
    </aop:config>

</beans>
2.3 结果和Maven
2.3.1 结果

Fa la la, the knight is so brave! Embarking on quest to slay the dragon! Tee hee hee, the brave knight did embark on a quest!

2.3.2 Maven

本节中利用到了AspectJ切点表达式,需要在Maven中添加如下依赖:

代码语言:javascript
复制
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.10</version>
</dependency>

<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.5.4</version>
</dependency>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.07.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 依赖注入
    • 1.1 实现
      • 1.2 注入
        • 1.3 装配
          • 1.3.1 xml配置
          • 1.3.2 Java描述配置
        • 1.4 实现
          • 1.4.1 xml配置的实现
          • 1.4.2 Java配置的实现
        • 1.5 上下文中其他类和结果
          • 1.5.1 上下文中其他类
          • 1.5.2 运行结果:
        • 1.5.3 Maven
        • 2 面向切面编程(AOP)
          • 2.1 AOP简单应用
            • 2.3 结果和Maven
              • 2.3.1 结果
              • 2.3.2 Maven
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档