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

1 依赖注入

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

1.1 实现

对于如下类

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的实现,例如如下类:

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配置
<?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描述配置
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配置文件)。

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。

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
package com.junzerg.spring_knight;

public interface Knight {

    void embarkOnQuest();

}
  1. Quest
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)依赖,如下:

<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中的骑士的事迹,用一个吟游诗人来记载。

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

<?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中添加如下依赖:

<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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容