io java 是什么意思 java ioc是什么模式_工厂模式


ABSTRACT

Spring的IOC(控制反转)是Spring框架的灵魂,有了它才有了Spring的很多其他的灵活的特性。使用 Spring 开发项目时,控制层、业务层、DAO 层都是通过 IoC 来完成依赖注入的。

IOC其实就是工厂模式+Java的反射机制,所以要理解IOC,我们必须要对工厂模式和反射机制有了解。

什么是IOC

在传统的程序开发中,当需要调用对象时,通常由调用者来创建被调用者的实例,即对象是由调用者主动 new 出来的。

但在 Spring 框架中创建对象的工作不再由调用者来完成,而是交给 IoC 容器来创建,再推送给调用者,整个流程完成反转,因此是控制反转

反射机制

反射(Reflection)是其Java非常突出的一个动态相关机制。它可以于运行时加载、使用编译期间完全未知的classes(但是要知道类的名字)。也就是说,在运行时,我们还可以获取一个类中所有的方法和属性,可以实例化任何类的对象,还能判断一个对象所属的类。

这样做的好处是,我们在程序运行时才会确定类型绑定对象,而不是在编译时。很多基础框架都用到了Java的这个机制,例如Spring框架、Struct等等,因为这些基础框架往往需要适用于不同的场景,因此对程序的灵活性要求很高,所以动态创建对象、获得类的信息就尤为有用。再比如,一个大型的软件发布后,如果需要更新功能,停止运行然后在重新编译是不现实的,如果利用了java的反射机制,就不需要为了新增加的功能重新编译程序。

反射机制的实现

我们可能之前就有见过反射机制的出现,就是在JDBC中加载数据库驱动时的

Class.forName(“com.mysql.jdbc.Driver”)

如果我们要使用一个类,就要获得这个类的反射类。有三种方法:

1. GETCLASS()方法

所有类的对象都是Class的实例。

String s = “Tomato”;
Class<?> c = s.getClass();

2. CLASS的静态方法FORNAME

Class<?> c = Class.forName(“Tomato”);

3. 知道类名,我们可以直接用.CLASS

Class<?> c = String.class;
实例化一个(构造函数不带参)类的对象:
Object obj = a.newInstance();
实例化一个(构造函数带参)类的对象:
Constructor constructor=c.getConstructor(String.class,int.class);
constructor.newInstance(“Java”,30);
获取对象中的所有方法:
Method[] methods = classType.getDeclaredMethods();
for (int i=0;i<methods.length;i++){
//获取方法名字
String methodName=methods[i].getName();
//获取本方法所有参数类型,存入数组
Class<?>[] parameterTypes = methods[i].getParameterTypes();
根据方法名用于获取Class类指代对象自己声明的某个方法 getDeclaredMethod();
Method m = c.getDeclaredMethod();
invoke(); 就可以触发方法
m.setAccessible(true);
m.invoke(c);

*不管是public,default,protect还是pricate方法,通过反射类我们都可以自由调用。(但是实际开发中不建议)

获取方法的注解

在Spring中注解扮演着很关键的角色,反射机制也能让我们获取方法的注解

m.getAnnotation(UseCase.class);

工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

使用场景:在我们明确地计划不同条件下创建不同实例时使用,而且通常情况下,客户代码不知道或不需要知道创建的对象是来自哪一个类(由服务提供者决定)。主要解决接口选择的问题。

简单的工厂模式

Shape.java 创建一个Shape接口
public interface Shape {
 void draw();
}
三个接口的实体类
Rectangle.java
public class Rectangle implements Shape {
 @Override
 public void draw() {
 System.out.println(“Inside Rectangle::draw() method.”);
 }
}
Square.java
public class Square implements Shape {
 @Override
 public void draw() {
 System.out.println(“Inside Square::draw() method.”);
 }
}
Circle.java
public class Circle implements Shape {
 @Override
 public void draw() {
 System.out.println(“Inside Circle::draw() method.”);
 }
}
工厂类,决定实例化哪一个类的对象
public class ShapeFactory {
 //使用 getShape 方法获取形状类型的对象
 public Shape getShape(String shapeType){
 if(shapeType == null){
 return null;
 } 
 if(shapeType.equalsIgnoreCase(“CIRCLE”)){
 return new Circle();
 } else if(shapeType.equalsIgnoreCase(“RECTANGLE”)){
 return new Rectangle();
 } else if(shapeType.equalsIgnoreCase(“SQUARE”)){
 return new Square();
 }
 return null;
 }
}

这个工厂模式有一个问题是,它的工厂类是静态的,如果我们需要增加产品类别,就必须要添加判断条件,这不符合面对对象的开放封闭原则。当然有其他的设计模式可以解决这个问题,例如工厂方法模式,把工厂类变为抽象类,在它的实现类里实例化对象,然后客户代码中,通过配置文件等来实例化工厂类的实体类。如果利用反射,可以轻松解决这个问题。

在工厂类中,我们提前不知道会需要实现什么类,只有在程序运行时我们才会知道。这就符合了反射机制的特性。

在工厂模式中加入反射机制:

public class ShapeFactory {
 public Shape getShape(String ClassName){
 if(shapeType == null){
 return null;
 } 
 Shape s = null;
 try{
 s = (Shape)Class.forName(ClassName).newInstance();
 }catch (Exception e) {
 e.printStackTrace();
 }
 return s;
 }
}

现在就算我们添加任意多个子类的时候,工厂类就不需要修改。当然,简单使用上述代码需要传入完整的包名和反射类名,用户可能并不知道,所以我们通过属性文件的形式配置所需要的子类。(属性文件就不说啦)

说回SPRING中的IOC

在Spring中,是在 spring.xml 中配置 bean 标签,IoC 容器通过加载 bean 标签来创建对象的。

BEAN有两种构造方法:有参构造和无参构造。

无参构造<bean id=”stu” class=”xyz.hahatomato.entity.Student”</bean>

有参构造

<bean id=”stu2″ class=”xyz.hahatomato.entity.Student”>
 <constructor-arg name=”id” value=”2″></constructor-arg>
 <constructor-arg name=”name” value=”番茄”></constructor-arg>
 <constructor-arg name=”age” value=”17″></constructor-arg>
</bean>

如何获得IOC创建的对象呢?

Spring提供了两种方法来获取这个对象:通过ID和运行时类

通过ID:

1.加载 spring.xml 配置文件

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“spring.xml”);

2.通过 id 值获取对象

Student stu = (Student) applicationContext.getBean(“stu”);

通过运行时类

1.加载 spring.xml 配置文件

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“spring.xml”);

2.通过运行时类获取对象

Student stu = applicationContext.getBean(Student.class);

System.out.println(stu);

什么是依赖注入?(DI)

依赖注入是将不同对象进行关联的一种方式。

例如创建了一个class对象后,再创建一个student对象,student对象中有一个属性是class,需要绑定刚刚创建的class。此时就需要用到依赖注入。

<!– 创建 classes 对象 –>
<bean id=”classe1″ class=”xyz.hahatomato.entity.Classes”>
<property name=”id” value=”1″></property>
<property name=”name” value=”小班”></property>
</bean>
<!– 创建 stu 对象 –>
<bean id=”stu2″ class=”xyz.hahatomato.entity.Student”>
<property name=”id” value=”2″></property>
<property name=”name” value=”fish”</property>
<property name=”age” value=”3″></property>
<!– 将 classes 对象赋给 stu 对象 –>
<property name=”classe” ref=”classe1″></property>
</bean>

如有疏漏,欢迎交流!