我们知道,spring提供的两大核心: ioc 以及 aop 这是从它的角度而言,那么从我们开发者的角度而言呢? 不可能说你很优秀,特别优秀,于是所有人都要臣服你吧 只能说你很优秀,特别优秀,能够给我们带来积极的影响,于是我们愿意臣服你 他对我们的终极意义就一个: 解耦 正如java开发最终的目标是开闭原则一样,我们需要这个优秀的特性,我来为大家科普一下关于简单谈谈对spring的理解?以下内容希望对你有帮助!

简单谈谈对spring的理解(Spring:解耦的理解)

简单谈谈对spring的理解

我们知道,spring提供的两大核心: ioc 以及 aop。 这是从它的角度而言,那么从我们开发者的角度而言呢? 不可能说你很优秀,特别优秀,于是所有人都要臣服你吧! 只能说你很优秀,特别优秀,能够给我们带来积极的影响,于是我们愿意臣服你。 他对我们的终极意义就一个: 解耦! 正如java开发最终的目标是开闭原则一样,我们需要这个优秀的特性。

根据老师的思路,自己再整理整理,然后看看它是如何解耦的。先根据我们通常使用的开发步骤而言:

定义一个抽象武器类:

package com.automannn;

/**

* @author com.automannn@163.com

* @time 2018/9/12 9:20

*/

public interface Weapon {

void attack();

}

package com.automannn.impl;

import com.automannn.Weapon;

/**

* @author com.automannn@163.com

* @time 2018/9/12 9:25

*/

public class Gun implements Weapon {

public void attack() {

System.out.println("用枪攻击了!");

}

}

package com.automannn.impl;

import com.automannn.Weapon;

/**

* @author com.automannn@163.com

* @time 2018/9/12 9:26

*/

public class Knife implements Weapon {

@Override

public void attack() {

System.out.println("用刀攻击了!");

}

}

定义持有武器的路人甲:

package com.automannn.entity;

import com.automannn.Weapon;

/**

* @author automannn@163.com

* @time 2018/10/9 13:36

*/

public class RudeMan {

public static final String NAME ="龙哥";

Weapon weapon;

public Weapon getWeapon() {

return weapon;

}

public void setWeapon(Weapon weapon) {

this.weapon = weapon;

}

public void attack(){

System.out.print(NAME ":");

weapon.attack();

}

}

启动测试类:

package com.automannn.test;

import com.automannn.entity.RudeMan;

import com.automannn.impl.Knife;

/**

* @author automannn@163.com

* @time 2018/10/9 13:42

*/

public class Main {

public static void main(String[] args) {

RudeMan rudeMan = new RudeMan();

rudeMan.setWeapon(new Knife());

rudeMan.attack();

}

}

运行结果:

spring 解耦的原因探究_bundle

何谓耦合呢?

比如,这个路人甲他带了有武器,这个武器可以是刀,但是不一定非得是刀。 但是其实这里代码的设计上已经不存在结构上的耦合了! 因为有本优秀的逐月工程师在! 哈哈。 那么这个时候存在另外一种耦合,就是运行时耦合! 什么意思呢? 就是当程序运行起来的时候,这个刀实际上与路人甲已经绑定在一起了。 称之为死耦合哈哈哈。 因为我们实际上是有这样的需求的,当项目发布上线了之后,需要根据某种策略动态的选择实现类,如果没有解耦的特性,那么框架不仅不能带来什么优势,反而降低程序效率,变成一个累赘。

第一种解耦方式: 工厂方法。

package com.automannn.factory;

import com.automannn.Weapon;

import com.automannn.impl.Dex;

import com.automannn.impl.Gun;

import com.automannn.impl.Knife;

/**

* @author automannn@163.com

* @time 2018/10/9 13:50

*/

public class WeaponFactory {

private Weapon weapon;

WeaponFactory(){}

public Weapon getInstance(int order) {

switch (order){

case 0:

weapon= new Dex();

break;

case 1:

weapon= new Knife();

break;

default:

weapon =new Gun();

}

return weapon;

}

}

这个时候,我在运行时,可以通过接收命令的方式动态的改变路人甲使用的武器了。

package com.automannn.test;

import com.automannn.entity.RudeMan;

import com.automannn.factory.WeaponFactory;

import com.automannn.impl.Knife;

/**

* @author automannn@163.com

* @time 2018/10/9 13:42

*/

public class Main {

public static void main(String[] args) {

RudeMan rudeMan = new RudeMan();

//rudeMan.setWeapon(new Knife());

rudeMan.setWeapon(WeaponFactory.getInstance(2));

rudeMan.attack();

}

}

但是这个时候我们需要注意,这种方式是实现类已经知道,但是我们保不定以后还要增加实现类。 因此这里仍然存在着较高的耦合性。

第二种解耦方式:配置文件的方式

由于工厂方式存在较告的耦合性,因此我们下面采用配置文件的方式解耦;

package com.automannn.property;

import com.automannn.Weapon;

import java.util.ResourceBundle;

/**

* @author automannn@163.com

* @time 2018/10/9 14:02

*/

public class PropertyHandler {

static Weapon weapon;

//读取配置文件,核心类为 Properties

//有三种实现方式,分别是: 基于ClassLoader,InputStream,和 java.util.ResouceBundle

public static Weapon getWeapon() {

//Properties properties = new Properties();

ResourceBundle rb = ResourceBundle.getBundle("test");

String weaponName= rb.getString("weapon");

try {

Object object = Class.forName(weaponName).newInstance();

weapon = (Weapon) object;

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

return weapon;

}

}

配置文件:

weapon = com.automannn.impl.Dex

1.

使用:

package com.automannn.factory;

import com.automannn.Weapon;

import com.automannn.impl.Dex;

import com.automannn.impl.Gun;

import com.automannn.impl.Knife;

import com.automannn.property.PropertyHandler;

/**

* @author automannn@163.com

* @time 2018/10/9 13:50

*/

public class WeaponFactory {

private static Weapon weapon;

WeaponFactory(){}

public static Weapon getInstance() {

weapon = PropertyHandler.getWeapon();

return weapon;

}

}

package com.automannn.test;

import com.automannn.entity.RudeMan;

import com.automannn.factory.WeaponFactory;

import com.automannn.impl.Knife;

/**

* @author automannn@163.com

* @time 2018/10/9 13:42

*/

public class Main {

public static void main(String[] args) {

RudeMan rudeMan = new RudeMan();

//rudeMan.setWeapon(new Knife());

rudeMan.setWeapon(WeaponFactory.getInstance());

rudeMan.attack();

}

}

就目前而言,我们应该是已经完全解除了它的耦合性,为什么说呢?

1,武器的实现类可以自己配置,自己配置包含两个含义: 配置系统种原有的其它实现类; 增加新增的实现类,不一定在包内部,只要能够被类加载器加载,哪怕放在rt.jar包里也行。

2,可以在程序外部配置,也就是在程序运行过程中,修改配置文件达到效果。

第三种解耦方式: 注解方式解耦,对配置文件的一种改进

在上面,我们增加一个实现类需要经过这样的步骤: 定义实现类---> 配置实现类。无形中我们需要做两个步骤才能达到我们的要求。关键是我们需要来回切换,在繁杂的配置文件中定位到想要的位置进行配置。 那么使用注解的方式好处就来了。

定义注解类:

package com.automannn.Annotation;

import java.lang.annotation.*;

/**

* @author automannn@163.com

* @time 2018/9/12 10:12

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

@Documented

public @interface Inject {

String value() default "";

}

定义注解处理类:,它是基于反射实现的。 但是实际上我们时时在用反射,就比如new User(), 那么它也是通过反射实现的。

package com.automannn.entity;

import com.automannn.Weapon;

import com.automannn.annotation.Inject;

import java.lang.annotation.Annotation;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

/**

* @author automannn@163.com

* @time 2018/9/12 10:17

*/

public class AnnotationHolder {

public AnnotationHolder() throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {

Method[] methods = Hero.class.getMethods();

for (Method m: methods){

Annotation annotation;

if ((annotation= m.getDeclaredAnnotation(Inject.class))!=null){

Inject inject = (Inject) annotation;

String weaponName= inject.value();

Weapon wp = (Weapon) Class.forName(weaponName).newInstance();

m.invoke(this,wp);

}

}

}

}

使用:

package com.automannn.entity;

import com.automannn.annotation.Inject;

import com.automannn.Weapon;

import java.lang.reflect.InvocationTargetException;

/**

* @author com.automannn@163.com

* @time 2018/9/12 9:28

*/

public class Hero extends AnnotationHolder{

Weapon weapon;

private String name;

public Hero(String name, Weapon weapon) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {

super();

this.name = name;

this.weapon = weapon;

}

public Hero() throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {

super();

}

public void attack(){

System.out.print(name " ");

weapon.attack();

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Weapon getWeapon() {

return weapon;

}

@Inject(value = "com.automannn.impl.Gun")

public void setWeapon(Weapon weapon) {

this.weapon = weapon;

}

}

到目前为止,我们就已经做到了完全解耦! 实际上在配置文件那里就已经完全解耦,这里更多的是提高了设计的内聚度更恰当一点吧!

-----------------------------------------------------------------------------------------

最后补充一下读取配置文件的几种方式,因为学了这么久的java,还没有自己去度过配置文件,我还是有点汗颜的。

第一种读取配置文件的方式:ClassLoader.getResourceAsStream,由官方提供的工具包中的工具,java.util.Properties解析。

Properties properties = new Properties();

// 使用ClassLoader加载properties配置文件生成对应的输入流

InputStream in = Base.class.getClassLoader().getResourceAsStream("test.properties");

// 使用properties对象加载输入流

try {

properties.load(in);

} catch (IOException e) {

e.printStackTrace();

}

//获取key对应的value值

properties.getProperty("weapon");

第二种读取配置文件的方式: new FileReader("")的方式读取,由官方提供的工具包中的工具,java.util.Properties解析。

Properties properties = new Properties();

// 使用InPutStream流读取properties文件

BufferedReader bufferedReader = null;

try {

bufferedReader = new BufferedReader(new FileReader("D:\\mydev\\demo\\src\\main\\resources\\test.properties"));

properties.load(bufferedReader);

properties.getProperty("weapon");

} catch (Exception e) {

e.printStackTrace();

}

第三种读取配置文件的方式: 由官方提供的工具包中的工具,java.util.ResourceBundle.getBundle()处理,并解析。

ResourceBundle rb = ResourceBundle.getBundle("test");

String weaponName= rb.getString("weapon");

try {

Object object = Class.forName(weaponName).newInstance();

this.weapon = (Weapon) object;

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

需要注意,以上三种方式都由java官方提供支持,不需要再依赖第三方的依赖包。

,