我们知道,spring提供的两大核心: ioc 以及 aop 这是从它的角度而言,那么从我们开发者的角度而言呢? 不可能说你很优秀,特别优秀,于是所有人都要臣服你吧 只能说你很优秀,特别优秀,能够给我们带来积极的影响,于是我们愿意臣服你 他对我们的终极意义就一个: 解耦 正如java开发最终的目标是开闭原则一样,我们需要这个优秀的特性,我来为大家科普一下关于简单谈谈对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官方提供支持,不需要再依赖第三方的依赖包。
,