java 反射 工厂_JAVA反射机制、工厂模式与SPRING 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

//获取方法名字

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有两种构造方法:有参构造和无参构造。

无参构造:

有参构造:

如何获得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。此时就需要用到依赖注入。

如有疏漏,欢迎交流!

Reference:

《Java设计模式》Steven John Metsker; William C. Wake

欢迎收藏我的blog:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值