Spring框架解析(spring笔记,持续更新)

2 篇文章 0 订阅

1、spring demo

1.1、写一个spring的demo

测试类

public class TestMain {

	public static void main(String[] args) throws Exception {
		
		  //1.声明注册bean
		  BeanDefined beanObj = new BeanDefined();
		  beanObj.setBeanId("teacher");
		  beanObj.setClassPath("com.kaikeba.beans.Teacher");
		  //beanObj.setScope("prototype");  //根据spring框架介绍,默认情况下就是单例的singleton
		  
		  List beanList = new ArrayList();
		  beanList.add(beanObj);//spring核心配置
		  
		  //2.声明一个Spring提供BeanFacotory
		  BeanFactory factory = new BeanFactory(beanList);
		 
		  
		  //3.开发人员向BeanFactory索要实例对象.
		  Teacher t= (Teacher) factory.getBean("teacher");
		  System.out.println("t="+t);
		  Teacher t2= (Teacher) factory.getBean("teacher");
		  System.out.println("t2="+t2);
		}
}

BeanFactory类,用于解析传入的beanId和创建实例对象

public class BeanFactory {
	
	   private List<BeanDefined> beanDefinedList;
	   private Map<String ,Object> SpringIoc;//已经创建好实例对象

	public List<BeanDefined> getBeanDefinedList() {
		return beanDefinedList;
	}

	
	public BeanFactory(List<BeanDefined> beanDefinedList) throws Exception {
		
		this.beanDefinedList = beanDefinedList;
		SpringIoc  = new HashMap(); //所有scope="singleton" 采用单类模式管理bean对象
		for(BeanDefined beanObj:this.beanDefinedList){
			if("singleton".equals(beanObj.getScope())){
				Class classFile= Class.forName(beanObj.getClassPath());
				Object instance= classFile.newInstance();
				SpringIoc.put(beanObj.getBeanId(), instance);
			}
		}
		
	}

	public void setBeanDefinedList(List<BeanDefined> beanDefinedList) {
		this.beanDefinedList = beanDefinedList;
	}
	
	public Object getBean(String beanId) throws Exception{
		   Object instance = null;
		   for(BeanDefined beanObj:beanDefinedList){
			     if(beanId.equals(beanObj.getBeanId())){
			    	 String classPath = beanObj.getClassPath();			    	 
					 Class classFile= Class.forName(classPath);
					 String scope=beanObj.getScope();
					 if("prototype".equals(scope)){//.getBean每次都要返回一个全新实例对象
						  instance= classFile.newInstance();
					 }else{
						 instance=SpringIoc.get(beanId);
					 }
					 return instance;
			     }
		   }
		   return null;
	}
}
public class BeanDefined {
	private String beanId;
	private String classPath;
	private String scope ="singleton";
	
	public String getScope() {
		return scope;
	}
	public void setScope(String scope) {
		this.scope = scope;
	}
	public String getBeanId() {
		return beanId;
	}
	public void setBeanId(String beanId) {
		this.beanId = beanId;
	}
	public String getClassPath() {
		return classPath;
	}
	public void setClassPath(String classPath) {
		this.classPath = classPath;
	}
	
}

通过这个例子,告诉了我们Spring的核心就是一个工厂类,在配置文件写的这些标签。 实际上只是作者自己定义的规则,规则里面告诉我们如何把java类信息交给当前spring。spring在运行过程中,在默认的场景下就是使用反射工厂来进行创建的

demo里面使用了单例模式去管理bean对象,第一次创建实例对象放到我们的容器中,第二次去IOC容器依靠beanId去获取创建好的单例对象

1.2、spring自定义动态工厂实现demo

好处: 不同的用户,对相同对象创建时有不同的要求,修改完成后只需要修改配置文件就可以了,需要对我们工程的类进行重新的编译。

ps:为了节省内存消耗,也可以用静态工厂的方式,静态工厂只需要在类名前面加static就可以了。配置文件也不需要再去加载class的路径。

在这里插入图片描述

1.3、bean后处理器demo (依赖sping工厂)

定义: 在bean对象创建之后,对它的某些行为进行拦截,所拦截行为的功能做一个相关的增强操作,叫做bean后处理器。

bean的后置处理器的出现暴露出了spring的作者真正的目的,spring真正想给我们的是bean的代理对象。而不是单纯的new 对象。

代理就是对行为的一种监控,能体现行为的就是接口,想要好用,必须要接口来修饰

//需要被代理的接口
public interface BaseService {
        public String doSome();
}
//需要被代理的接口的实现类
public class ISomeService implements BaseService {
		public String doSome() {
		// TODO Auto-generated method stub
		return "Hello mike";//增强效果,doSome方法返回值都是大写
	}

}

完成类注册

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation=" http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
   
      <!-- 注册bean:被监控实现类 -->
      <bean id="isomeService" class="com.kaikeba.serviceImpl.ISomeService"></bean> 
      <!-- 注册代理实现类 -->
      <bean class="com.kaikeba.util.MyBeanPostProcessor"></bean> 
  

</beans>
//bean为当前的实例对象。beanName为当前bean的名称
public class MyBeanPostProcessor implements BeanPostProcessor {

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws Exception 
		System.out.println("bean对象初始化之前。。。。。");
		return bean;l
		//return  bean对象监控代理对象
	}

	public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws Exception {
		// 为当前bean对象注册代理监控对象,负责增强bean对象方法能力
		Class beanClass = beanInstance.getClass();
		if (beanClass == ISomeService.class) {
							/*
						 * 
						 *beanInstance.getClass().getClassLoader()当前类对象的类文件
						 *beanInstance.getClass().getInterfaces()拦截对象的行为
						 *new InvocationHandler()new反射机制包的接口(接口作为内置对象的时候是可以new的
						 **/
			Object proxy = Proxy.newProxyInstance(beanInstance.getClass().getClassLoader(),
					beanInstance.getClass().getInterfaces(), new InvocationHandler() {
						/*
						 * 
						 * method:doSome(需要拦截的方法) args:doSome执行接受实参 proxy:代理监控对对象
						 **/
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							System.out.println("ISomeService doSome 被拦截");
							String result = (String) method.invoke(beanInstance, args);// beanInstance.doSome
							return result.toUpperCase();
						}

					});
			return proxy;          //返回代理监控对象
		}
		return beanInstance;
	}

测试一下,最终输出的信息变成了大写

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("spring_config.xml");
		//向spring工厂获取代理类的bean,代理就是对行为的一种监控,能体现行为的就是接口,想要好用,必须要接口来修饰
		BaseService serviceObj = (BaseService) factory.getBean("isomeService");
		System.out.println(serviceObj.doSome());
	}
}

小知识:实例化指的是去创建这个类的实例对象。初始化是对当前实例对象的相关属性做处理。

抛出问题:spirng容器的实质就是一个工厂,是帮助我们创造对象的。如果spring容器关闭,那它所创建的bean对象是不是就会消亡呢?

答案是:并不会,在java的世界中,对象什么时候被干掉是有依据的,例如一个bean对象,早期是由spring框架的工厂类创建的,最终这个对象是要交给我们的开发人员的。开发人员也会去创建一个相关的引用对象,这个引用对象也指向它。所以bean对象还有其他的引用对象,所以创建的bean对象是不会消亡的

1.3.1、bean后处理器demo(使用自定义工厂)

public class BeanFactory {
	   //private List<BeanDefined> beanDefinedList;
	   //private Map<String ,Object> SpringIoc;//已经创建好实例对象
	   private BeanPostProcessor processorObj;//增加后置对象
	   
		//public List<BeanDefined> getBeanDefinedList() {
			//return beanDefinedList;
	//}


		//public BeanFactory(List<BeanDefined> beanDefinedList) throws Exception {
		//this.beanDefinedList = beanDefinedList;
		//SpringIoc  = new HashMap(); //所有scope="singleton" 采用单类模式管理bean对象
		//for(BeanDefined beanObj:this.beanDefinedList){
			//if("singleton".equals(beanObj.getScope())){
				//Class classFile= Class.forName(beanObj.getClassPath());
				//Object instance= classFile.newInstance();
				
				//判断当前对象是一个bean对象还是后置处理处理对象
				isProcessor(instance,classFile);
				SpringIoc.put(beanObj.getBeanId(), instance);
			}
		}
		
	}
	//传入实例对象和所关联的类文件
    private void isProcessor(Object instance,Class classFile){
    				//查看类文件实现的接口,可能有多个接口,用数组去接收
    	         Class interfaceArray[] = classFile.getInterfaces();
    	         //判空
    	         if(interfaceArray==null){
    	        	 return;
    	         }
    	         
    	         for(int i=0;i<interfaceArray.length;i++){
    	        	 Class interfaceType = interfaceArray[i];
    	        	 //所有的后置处理对象都需要实现BeanPostProcessor
    	        	 //判断这个接口类型是不是BeanPostProcessor.class
    	        	 if(interfaceType == BeanPostProcessor.class){//证明当前实例对象是后置处理器
    	        		 this.processorObj = (BeanPostProcessor)instance;
    	        	 }
    	         }
    }

	//public Object getBean(String beanId) throws Exception{
		   //Object instance = null;
		   Object proxyObj = null;//当前实例对象的代理监控对象
		  //for(BeanDefined beanObj:beanDefinedList){
			     //if(beanId.equals(beanObj.getBeanId())){
			    	 //String classPath = beanObj.getClassPath();			    	 
					 //Class classFile= Class.forName(classPath);
					 //String scope=beanObj.getScope();
					 //String factoryBean = beanObj.getFactoryBean();
					 //String factoryMehtod=beanObj.getFactoryMethod();
					 //if("prototype".equals(scope)){//.getBean每次都要返回一个全新实例对象
						  
						  //if(factoryBean!=null && factoryMehtod!=null){//用户希望使用指定工厂创建实例对象
							       //Object factoryObj=  SpringIoc.get(factoryBean);
							       //Class factoryClass=factoryObj.getClass();
							      // Method methodObj= //factoryClass.getDeclaredMethod(factoryMehtod, null);
							       //methodObj.setAccessible(true);
							       //instance= methodObj.invoke(factoryObj, null);
						  //}else{
							 // instance= classFile.newInstance();
						  //}
					 //}else{
						 //instance=SpringIoc.get(beanId);
					 //}
					 
					 //前置,传入实例对象和所关联的ID
					 if(this.processorObj!=null){
						proxyObj = this.processorObj.postProcessBeforeInitialization(instance, beanId);
						 
						 //实例对象初始化。Spring依赖注入
						 proxyObj = this.processorObj.postProcessAfterInitialization(instance, beanId);
						 //此时返回proxyObj可能就是原始bean对象,也有可能就是代理对象
						 return proxyObj;
					 }else{
						 return instance;
					 }
				}
		   }
		   return null;
	}
}

测试一下

public class TestMain {

	public static void main(String[] args) throws Exception {
		
		  //1.声明注册bean
		
		  
		  BeanDefined beanObj = new BeanDefined();
		  beanObj.setBeanId("isomeService");
		  beanObj.setClassPath("com.kaikeba.serviceImpl.ISomeService");
		 
		  
		  BeanDefined beanObj2 = new BeanDefined();		
		  beanObj2.setClassPath("com.kaikeba.util.MyBeanPostProcessor");
		  
		  List configuration = new ArrayList();
		  configuration.add(beanObj);//spring核心配置
		  configuration.add(beanObj2);
		  
		  //2.声明一个Spring提供BeanFacotory
		  BeanFactory factory = new BeanFactory(configuration);
		 
		  
		  //3.开发人员向BeanFactory索要实例对象.
		  BaseService t= (BaseService) factory.getBean("isomeService");
		  System.out.println("t="+t);
		  System.out.println(t.doSome());//HELLO MIKE
	}
}

1.4 依赖注入DI(spring容器是如何做的)

上面都是sping 容器对bean对象实例化的过程,未涉及初始化。

初始化的过程我们把它称为依赖注入,依赖工厂为对象中属性赋值处理,叫做依赖注入。

ps:个人认为依赖注入是spring里面最简单得知识点,只要学习过反射,这个事情就不难。

完成依赖注入配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation=" http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
   
        <bean id="teacher" class="com.kaikeba.beans.Teacher">
            <property name="teacherName" value="Mr Luo"></property>
            <property name="friendArray" value="mike,allen,tom"></property>
            <property name="school"      value="杭州测试、杭州java开发、杭州前端开发"></property>
        </bean>
  </beans>

测试

public class TestMain {
	public static void main(String[] args) {
		ApplicationContext factory = new ClassPathXmlApplicationContext("spring_config.xml");
		Teacher teacher = (Teacher) factory.getBean("teacher");
		System.out.println(teacher.getTeacherName());
		System.out.println(teacher.getFriendArray());
		System.out.println(teacher.getSchool());
		//分别打印出xml配置文件中的value
	}
}

1.4.1依赖注入DI(自定义实现)

这个类相当于xml管理得标签

@Data
public class BeanDefined {
	/*
	 * 
	 *   这个类相当于xml管理得标签
	 *   <bean id  ,class,  scope.factory-bean,factory-method>
	 **/
	private String beanId;
	private String classPath;
	private String scope ="singleton";
	private String factoryBean=null;
	private String factoryMethod=null;
	private Map<String,String> propertyMap=new HashMap();
}

依赖注入得实现

public class BeanFactory {
	
	private List<BeanDefined> beanDefinedList;
	private Map<String ,Object> SpringIoc;//已经创建好实例对象
	private BeanPostProcessor processorObj;//后置对象
	   
	public List<BeanDefined> getBeanDefinedList() {
		return beanDefinedList;
	}
	
	//依赖注入(传入实例对象、实例对象关联的类文件、propertyMap)
	public void setValue(Object instance,Class classFile,Map propertyMap) throws NoSuchFieldException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		     //循环遍历  propertyMap<属性名,属性值> 
		     //获取类的所有方法
		     Method methodArray[]= classFile.getDeclaredMethods();
		     //获取所有的key
		     Set fieldNameSet = propertyMap.keySet();
		     Iterator fieldIterator = fieldNameSet.iterator();
		     while(fieldIterator.hasNext()){
		     	 //拿到属性名
		    	 String fieldName = (String) fieldIterator.next();
		    	 //拿到对应的value
		    	 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;// sid == setsid
		    		 if(methodName.equalsIgnoreCase(methodObj.getName())){
		    			   //配置文件全写成string了,实际上很多不是,要判断一下
		    			   //获取属性的数据类型 Integer,String,Double,boolean,list
		    			   Class fieldType=   fieldObj.getType();
		    		       	//分别判断
		    		 		if(fieldType == String.class){
		    		    	   methodObj.invoke(instance, value);
		    		       }else if(fieldType == Integer.class){
		    		    	   methodObj.invoke(instance, Integer.valueOf(value));
		    		       }else if(fieldType == Boolean.class){
		    		    	   methodObj.invoke(instance, Boolean.valueOf(value));
		    		       }else if(fieldType==List.class){
		    		    	     List tempList = new ArrayList();
		    		    			//value以逗号分隔,全部取出交给数组
								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;
		    		 }
		    	 }
		     }
	}
	
	public BeanFactory(List<BeanDefined> beanDefinedList) throws Exception {
		
		this.beanDefinedList = beanDefinedList;
		SpringIoc  = new HashMap(); //所有scope="singleton" 采用单类模式管理bean对象
		for(BeanDefined beanObj:this.beanDefinedList){
			if("singleton".equals(beanObj.getScope())){
				Class classFile= Class.forName(beanObj.getClassPath());
				Object instance= classFile.newInstance();
				//判断当前对象是一个bean对象还是后置处理处理对象
				isProcessor(instance,classFile);
				SpringIoc.put(beanObj.getBeanId(), instance);
			}
		}
		
	}
    private void isProcessor(Object instance,Class classFile){
    //getInterfaces()方法获得这个对象所实现的接口。
    	         Class interfaceArray[] = classFile.getInterfaces();
    	         if(interfaceArray==null){
    	        	 return;
    	         }
    	         
    	         for(int i=0;i<interfaceArray.length;i++){
    	        	 Class interfaceType = interfaceArray[i];
    	        	 if(interfaceType == BeanPostProcessor.class){//证明当前实例对象是后置处理器
    	        		 this.processorObj = (BeanPostProcessor)instance;
    	        	 }
    	         }
    }
	
	public void setBeanDefinedList(List<BeanDefined> beanDefinedList) {
		this.beanDefinedList = beanDefinedList;
	}
	
	public Object getBean(String beanId) throws Exception{
		   Object instance = null;
		   Object proxyObj = null;//当前实例对象的代理监控对象
		   for(BeanDefined beanObj:beanDefinedList){
			     if(beanId.equals(beanObj.getBeanId())){
			    	 String classPath = beanObj.getClassPath();			    	 
					 Class classFile= Class.forName(classPath);
					 String scope=beanObj.getScope();
					 String factoryBean = beanObj.getFactoryBean();
					 String factoryMehtod=beanObj.getFactoryMethod();
					 Map propertyMap = beanObj.getPropertyMap();
					 if("prototype".equals(scope)){//.getBean每次都要返回一个全新实例对象
						  
						  if(factoryBean!=null && factoryMehtod!=null){//用户希望使用指定工厂创建实例对象
							       Object factoryObj=  SpringIoc.get(factoryBean);
							       Class factoryClass=factoryObj.getClass();
							       Method methodObj= factoryClass.getDeclaredMethod(factoryMehtod, null);
							       methodObj.setAccessible(true);
							       instance= methodObj.invoke(factoryObj, null);
						  }else{
							  instance= classFile.newInstance();
						  }
					 }else{
						 instance=SpringIoc.get(beanId);
					 }
					 
					 if(this.processorObj!=null){
						 proxyObj = this.processorObj.postProcessBeforeInitialization(instance, beanId);
						 //实例对象初始化。Spring依赖注入
						 setValue(instance,classFile,propertyMap);
						 proxyObj = this.processorObj.postProcessAfterInitialization(instance, beanId);
						 //此时返回proxyObj可能就是原始bean对象,也有可能就是代理对象
						 return proxyObj;
					 }else{
						 //实例对象初始化
						 setValue(instance,classFile,propertyMap);
						 return instance;
					 }
			    }
		   }
		   return null;
	}
}

测试类

public class TestMain {

	public static void main(String[] args) throws Exception {
		
		  //1.声明注册bean
		
		  
		  BeanDefined beanObj = new BeanDefined();
		  beanObj.setBeanId("teacher");
		  beanObj.setClassPath("com.kaikeba.beans.Teacher");
		  /*
		   *  <property>
		   * 
		   **/
		  Map<String, String> propertyMap =  beanObj.getPropertyMap();
		  propertyMap.put("teacherName", "李老师");
		  propertyMap.put("friendArray", "老刘,老孙,小师妹");
		  propertyMap.put("school", "清华一小,北京理工大学");
		   
		  List configuration = new ArrayList();
		  configuration.add(beanObj);//spring核心配置
		
		  
		  //2.声明一个Spring提供BeanFacotory
		  BeanFactory factory = new BeanFactory(configuration);
		 
		  
		  //3.开发人员向BeanFactory索要实例对象.
		  Teacher t= (Teacher) factory.getBean("teacher");
		  System.out.println("t="+t);
		  //打印出初始化数据
		  System.out.println(t.getTeacherName());
		 }
}

1.5 AOP

AOP即代理设计模式实现细节:用较少的代码实现一个简单的代理模式

如果不用AOP,实现一个代理模式需要实现的步骤

  • 声明接口:注册需要被监听行为名称
  • 接口实现类: 扮演被监控的类,负责被监听方法实现细节
  • InvocationHanler接口实现类:
    1.次要业务/增强业务
    2.将次要业务与被监听方法绑定执行
  • 代理监控对象:
    1.被监控类内存地址,被监控类实现的接口,
    2.InvocationHandler实现类的实例对象

Spring AOP:简化代理模式实现步骤

  • 声明接口:注册需要被监听行为名称
  • 接口实现类: 扮演被监控的类,负责被监听方法实现细节
  • 次要业务/增强业务

1.5.1AOP编程术语

  • 切面(Aspect)

说白了就是次要业务

  • 目标对象(Target)

当前需要监控的某个实例对象

  • 织入(Weaving)
    将切面插入到目标对象的目标方法的过程,即invoke行为
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值