1、IOC控制反转:控制什么?反转什么?
控制:指选择接口的实现类控制权
反转:指把这种控制权从代码中移除交由spring容器管理
2、IOC的类型
1)、构造器注入
public class ConstructorInjection{
private InterfaceClass interClazz;
public ConstructorInjection(InterfaceClass interClazz){
this.interClzaa = interClazz;
}
public void yourMethod(){
interClzaa.someMethod();
}
}
2)、属性注入(也有叫get、set注入)
public class FieldsInjection{
private InterfaceClass interClazz;
public void setInterClazz(InterfaceClass interClazz){
this.interClzaa = interClazz;
}
public void yourMethod(){
interClzaa.someMethod();
}
}
3、通过容器完成IOC;在applicationContext.xml中配置,代码片段如下
<bean id="interClazz" class="ImplClass" />
<bean id="fieldsInjection" class="FieldsInjection" p:interClazz-ref="interClazz" />
4、IOC原理
1)、简单示例:通过反射机制对实例化一个类
package com.keivndai.comomtest;
public class Car {
private String brand;
private String color;
private int maxSpeed;
//无参构造函数
public Car() {
}
//有参构造函数
public Car(String brand, String color, int maxSpeed) {
this.brand = brand;
this.color = color;
this.maxSpeed = maxSpeed;
}
//篇幅问题,此处get、set方法省略
}
package com.keivndai.comomtest;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static Car initByDefaultConst() throws Exception{
//通过类加载器加载Car
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> clazz = loader.loadClass("com.keivndai.comomtest.Car");
//获取默认的构造函数,实例化Car
Constructor<?> cons = clazz.getConstructor((Class[])null);
Car car = (Car)cons.newInstance();
//通过反射机制赋值
Method setBrand = clazz.getMethod("setBrand", String.class);
setBrand.invoke(car, "benz");
Method setColor = clazz.getMethod("setColor", String.class);
setColor.invoke(car, "black");
//此处只能用int不能用Integer;应该与方法中参数类型一致
Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
setMaxSpeed.invoke(car, 250);
return car;
}
public static void main(String[] args) throws Exception {
Car car = ReflectTest.initByDefaultConst();
car.introduce();
//输出Car [brand=benz, color=black, maxSpeed=250]
}
}
补充知识点:
1、类装载器ClassLoader的工作机制:类装载器就是寻找类的字节码文件并在JVM中的构造类的对象组件
类装载器把一个类装入JVM要经过以下步骤
1)、装载:查找和导入Class文件
2)、校验:检查载入Class文件数据的正确性
3)、准备:给类的静态变量分配空间
4)、解析:将符号引用转成直接引用(可选,通过)
5)、初始化:对类的静态变量、静态代码块执行初始化(这里又能引出问题java类的初始化顺序,这里有java类的初始化顺序)
类文件被装载以后,在JVM中拥有一个类描述对象,该类的所有实例都拥有指向这个类描述对象的引用,而该类描述对象又拥有指向关联ClassLoader的引用.关系如下图(其实我可以画的更准确、更细致,但麻烦将就一下)
2、java反射机制
反射机制最主要有三个反射类Constructor、Method、Fields(在java.reflect包中).通过反射机制能够访问到私有属性、方法,demo如下
ps.这里有个地方我本来掌握的不准确,这次复习了解了
原来写一个通过属性名给属性赋值的功能时,知道fieldName之后我是先拉拼接setFiled,再通过反射获取setField方法,再使用setFiled.invoke(obj,value)来给filed赋值;其实通过fieldName获取Field,再filed.set(obj,value)即可,代码更简单清爽
package com.keivndai.comomtest;
public class PrivateCar {
private String color;
protected void drive(){
System.out.println("drive my " + color + " car!");
}
}
package com.keivndai.comomtest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 这个demo的关键之处在于,通过反射机制能够访问私有的方法、属性
* @ClassName: PrivateCarReflect
* @author kevindai
* @date 2016-8-17 下午10:28:12
*
*/
public class PrivateCarReflect {
public static void main(String[] args) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> clazz = cl.loadClass("com.keivndai.comomtest.PrivateCar");
PrivateCar privateCar = (PrivateCar) clazz.newInstance();
Field field = clazz.getDeclaredField("color");
field.setAccessible(true);
field.set(privateCar, "red");
Method method = clazz.getDeclaredMethod("drive");
method.setAccessible(true);
method.invoke(privateCar);
//输出:drive my red car!
}
}
3、资源抽象接口Resource
- ps:web工程中classpath指web-inf/classes文件夹
- ”classpath:”:只会在第一个加载的com.xxx.xxx包下查找
- “classpath*”:会扫描到所有这些jar包及类路径下出现的com.xxx.xxx类路径
- 如:有个名为kevindai的应用共分为3个模块,每个模块都有一个配置文件,分别为module1.xml、module2.xml、module3.xml,都入在com.kevindai目录下,每个模块单独打包,这时使用”classpath:com/kevindai/module*.xml”只会加载第一个模块的配置文件;而使用”classpath*:com/kevindai/module*.xml”则会加载三个模块的配置文件
- pps.这里使用的*为Ant风格资源地址匹配符;有以下几种
- ?:匹配文件名中一个字符(如:classpath*:com/kevindai/mod?le.xml)
- :匹配文件名中任意个字符(如:classpath:com/kevindai/mod*.xml)
- :匹配多层路径(如:classpath:com//mod*.xml)
5、spring Bean的配置文件
- 基于xml配置:<bean id=”test” class=”com.kevindai.Test”/>
- 适合场景:
- bean来源于第三方库,如dataSource,JdbcTemplate,因无法使用注解,因此通过xml配置较好
- 命名空间配置 ,如aop、context等,只能采用xml配置
- 基于注解配置:@Compoent以及衍生的@Service、@Controller、@Repository
- 适合场景:Bean的实现类是在当前项目中开发的
- 基于java类配置:@Configuration
- 适合场景:优势在于可以通过代码方式控制bean初始化整体逻辑;因此适合实例化复杂的bean
- 其它零碎点
- @Autowire spring提供,默认byType,可以设置为可为Null,如果重名则启动报错(最强大)
- @Resource j2EE提供,默认byName,不能为Null
- @Injec j2EE提供,基本与@Autowire一致,不能为Null