第一章 mybatis 框架
在了解spring 框架之前,应该先了解mybatis 框架
第二章 spring 框架使用,动态工厂,依赖注入,
今天讲解了 spring 对 bean 是怎么管理的,怎么拦截的,spring怎么对属性做依赖注入的
2.1 平时的使用
1. 定义类
2. 根据规则定义配置文件
3. 通过工厂配置使用,可以把创建的对象监控起来,通过偷梁换柱的代理模式管理对象
2.2 模拟简单的spring 框架处理
1. beandefind
public class BeanDefined {
// attr
private String beanId;
private String classPath;
// getter & setter
}
2. beanFactory
// 就是一系列bean对象的标签集合
public class BeanFactory {
// 管理 bean对象
private List<BeanDefined> beanDefinedList;
// 提供一个获取bean的方法
public Object getBean(String beanId) throws Exception {
Object instance;
for (BeanDefined beanDefined: beanDefinedList){
if (beanDefined.getBeanId().equals(beanId)){
String classPath = beanDefined.getClassPath();
// 默认情况下,spring工厂通过调用当前类默认构造方法创建实例对象
Class classFile = Class.forName(classPath);
instance = classFile.newInstance();
return instance;
}
}
return null; // 没找到返回空
}
}
3. 测试类
public class MainTest {
public static void main(String[] args) throws Exception {
// 1 声明注册bean
BeanDefined beanObj = new BeanDefined();
beanObj.setBeanId("teacher");
beanObj.setClassPath("beans.Teacher");
List beanList = new ArrayList();
beanList.add(beanObj); // spring 核心配置,添加管理一个个bean标签对象
// 2 声明一个spring 提供 Beanfactory
BeanFactory factory = new BeanFactory();
factory.setBeanDefinedList(beanList);
// 3 开发人员向 beanfactory 索要实例对象
Teacher t = (Teacher) factory.getBean("teacher");
System.out.println(t);
}
}
2.3 模拟spring IOC 容器,scope 属性,分别是 singleton prototype 两种对象创建方式
2.4 spring 也允许自己创建对象,动态创建对象 - 动态工厂
不同场景下,对象的创建 不一样
2.4.1 动态工厂的使用
1. 创建自定义工厂
2.在配置文件中注册
2.4.2 动态工厂的实现teacherFactory
框架的设计 = 设计模式 + 反射机制 + 规则
2.4.3 除了动态,spring也允许用户创建静态工厂
节省内存
public class TeacherFactory {
public static Teacher createTecher(){ // static 节省内存消耗
Teacher teacher = new Teacher();
System.out.println("teacherfactory 负责创建teacher对象");
return teacher;
}
}
2.5 BeanPostProcessor, 监控代理使用 & 源码的实现
2.5.1 监控代理使用
在这个bean对象在被创建之后,在它的某些行为里拦截,并对所拦截的功能做一个相关的增强操作,
1 增强 - 创建接口实现
public interface BaseService {
public String doSome();
}
public class ISomeService implements BaseService {
public String doSome() {
// 增强效果,doSome方法返回值都是大写
return "hello youngpeng";
}
}
2. 代理监控 - bean 后 增强
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean对象初始化之前.........");
return bean; // 返回bean或者bean对象监控的代理对象
}
public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws BeansException {
// 为当前的bean对象注册代理监控对象, 负责增强bean对象方法能力
Class beanClass = beanInstance.getClass();
/**
* 这里我们做了一个监控,这里交给用户的就不是一个真实的对象了,代理对象
*/
if (beanClass == ISomeService.class){
Object proxy = Proxy.newProxyInstance(beanInstance.getClass().getClassLoader(), // 当前对象类属的类文件在哪里
beanInstance.getClass().getInterfaces(), // 对象的那些行为要进行监控
new InvocationHandler() { // 拦截之后怎么做处理呢?
/**
* @param proxy : 代理监控对象
* @param method: doSome() 监控的方法
* @param args: dosome方法运行时接受的实参
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("isomeservice dosome 方法别拦截...");
String result = (String) method.invoke(beanInstance, args);
return result.toUpperCase();
}
}
);
return proxy;
}
return beanInstance;
}
}
3 增强之后就开始注册了,在配置类中实现
4 测试使用
2.5.2 BeanPostProcessor 源码的实现
1 书写自己的BeanPostProcessor 接口
public interface BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception ;
public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws Exception;
}
2 书写自己的实现
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception {
System.out.println("bean对象初始化之前.........");
return bean; // 返回bean或者bean对象监控的代理对象
}
public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws Exception {
// 为当前的bean对象注册代理监控对象, 负责增强bean对象方法能力
Class beanClass = beanInstance.getClass();
/**
* 这里我们做了一个监控,这里交给用户的就不是一个真实的对象了,代理对象
*/
if (beanClass == ISomeService.class){
Object proxy = Proxy.newProxyInstance(beanInstance.getClass().getClassLoader(), // 当前对象类属的类文件在哪里
beanInstance.getClass().getInterfaces(), // 对象的那些行为要进行监控
new InvocationHandler() { // 拦截之后怎么做处理呢?
/**
* @param proxy : 代理监控对象
* @param method: doSome() 监控的方法
* @param args: dosome方法运行时接受的实参
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("isomeservice dosome 方法别拦截...");
String result = (String) method.invoke(beanInstance, args);
return result.toUpperCase();
}
});
return proxy;
}
return beanInstance;
}
}
2.6 依赖注入 使用 & 源码分析
让spring factory 对我们的对象进行实例化操作
spring 框架通过反射机制,调用属性对应的set方法进行赋值
2.6.1 依赖注入使用
1 编写实体类
2 spring 配置文件 - 读取标签信息,通过反射调用
3 工厂去读,直接使用
2.6.2 DI源码实现
我们怎么让标签对象化的去显示呢?
1. 定义类
public class Teacher {
private String teacherName;
private String friendArray[];
private List<String> school;
}
2. 写 beanDefind(添加一个map存放XML属性键值对)
public class BeanDefined {
/**
* <bean id, class, scope, factory-bean, factory-method > <bean/>
*/
private String beanId;
private String classPath;
private String scope ;
private String factoryBean = null; // 不用判断空字符串了
private String factoryMethod = null;
private Map<String, String> propertyMap = new HashMap<String, String>();
}
3. 写测试类 - 注册声明bean
/**
* 1 声明注册bean
*/
BeanDefined beanObj = new BeanDefined();
beanObj.setBeanId("teacher");
beanObj.setScope("prototype"); // singleton prototype
beanObj.setClassPath("beans.Teacher");
/**
* 依赖注入相关的配置写入 map 中
*/
Map<String, String> propertyMap = beanObj.getPropertyMap();
propertyMap.put("teacherName", "李老师");
propertyMap.put("friendArray", "桂桂,花花,丽丽");
propertyMap.put("school", "北小, 北大, 中科院");
4. 依赖注入: 反射 + set 方法
/**
* 依赖注入,赋值,类型转换
* @param instance 反射对应配置文件的bean 实例
* @param classFile bean 实例 对应的类文件
* @param propertyMap 配置文件中属性值
*/
public void setValue(Object instance, Class classFile, Map propertyMap) throws Exception {
// 循环遍历 propertyMap<属性名,属性值>
Method[] methodArray = classFile.getDeclaredMethods(); // 类文件getter setter 等方法
Set fieldNameSet = propertyMap.keySet(); // 解析出配置文件的map中key值
Iterator fieldIterator = fieldNameSet.iterator();
while (fieldIterator.hasNext()){
String fieldName = (String) fieldIterator.next();
String value = (String) propertyMap.get(fieldName);
Field fieldObj = classFile.getDeclaredField(fieldName);
for (int i=0;i<methodArray.length;i++){
Method methodObj = methodArray[i];
String methodName = "set" + fieldName; // 找到对应属性的set方法设置赋值
if (methodName.equalsIgnoreCase(methodObj.getName())){
Class fieldType = fieldObj.getType(); // 反射拿到属性是什么类型
/**
* 进行类型的转换
*/
if (fieldType == String.class){
methodObj.invoke(instance, value);
}else if(fieldType == Integer.class){
methodObj.invoke(instance, Integer.valueOf(value)); // 转换为int类型
}else if(fieldType == Boolean.class){
methodObj.invoke(instance, Boolean.valueOf(value));
}else if(fieldType == List.class){
List tempList = new ArrayList();
String dataArray[] = value.split(",");
for (int j=0;j<dataArray.length;j++){
tempList.add(dataArray[j]);
}
methodObj.invoke(instance, tempList);
}else { // 默认如果是数组类型
String[] dataArray = value.split(",");
Object data[] = new Object[1];
data[0] = dataArray;
methodObj.invoke(instance, data);
}
break;
}
}
}
}