Spring框架的两大特性:IOC、AOP
1,IOC特性
IOC:IOC,另外一种说法叫DI(Dependency Injection),即依赖注入。它并不是一种技术实现,而是一种设计思想。
在任何一个有实际开发意义的程序项目中,我们会使用很多类来描述它们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑。这个时候,每个类都需要负责管理与自己有交互的类的引用和依赖,代码将会变的异常难以维护和极度的高耦合。而IOC的出现正是用来解决这个问题,我们通过IOC将这些相互依赖对象的创建、协调工作交给Spring容器去处理,每个对象只需要关注其自身的业务逻辑关系就可以了。在这样的角度上来看,获得依赖的对象的方式,进行了反转,变成了由Spring容器控制对象如何获取外部资源(包括其他对象和文件资料等等)。
大白话就是:
我们在完成一些生产生活劳作【业务逻辑】的时候,需要使用到其他的工具【其他实例化对象-如斧头、镰刀、马车等】;在之前我们都是自己去实例化【自给自足-手动new一个个工具】,效率很低。
到了现代社会【Spring类似框架出现后】,我们自用关注我们的工作和生活就行了,其他的那些工具交给这个现代社会【Spring来进行对象的实例化】去完成。
以前是,我们主动去new一个工具,现在变成被动的接收工具。你现在不可能自己去造一辆地铁了吧!直接我要用的话,直接去用就完事了。
2,AOP特性
AOP:面向切面编程,往往被定义为促使软件系统实现关注点的分离的技术。
系统是由许多不同的组件所组成的,每一个组件各负责一块特定功能。除了实现自身核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的核心服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为它们会跨越系统的多个组件。
通知: 通知定义了切面是什么以及何时使用的概念。Spring 切面可以应用5种类型的通知:
- 前置通知(Before):在目标方法被调用之前调用通知功能。
- 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么。
- 返回通知(After-returning):在目标方法成功执行之后调用通知。
- 异常通知(After-throwing):在目标方法抛出异常后调用通知。
- 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
连接点:是在应用执行过程中能够插入切面的一个点。
切点: 切点定义了切面在何处要织入的一个或者多个连接点。
切面:是通知和切点的结合。通知和切点共同定义了切面的全部内容。
引入:引入允许我们向现有类添加新方法或属性。
织入:是把切面应用到目标对象,并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期中有多个点可以进行织入:
编译期: 在目标类编译时,切面被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标加载到JVM时被织入。这种方式需要特殊的类加载器(class loader)它可以在目标类被引入应用之前增强该目标类的字节码。
运行期: 切面在应用运行到某个时刻时被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。
3,tiny-Spring
参考-黄亿华的tiny-Spring
3.1 Step1
BeanFactory.java工厂模式接口
package com.cnblogs.Factory; public interface BeanFactory { /** * 工厂模式中的接口,用于产生实体类 * @param name * @return * @throws Exception */ Object getBean(String name) throws Exception; }
AbstractBeanFactory.java注册表类型【登记已经有的实例】
package com.cnblogs.Factory; import com.cnblogs.bean.BeanDefinition; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class AbstractBeanFactory implements BeanFactory { private Map<String, BeanDefinition> beanDefinitionMap=new ConcurrentHashMap<String, BeanDefinition>();//线程安全-散列表 private final List<String> beanDefinitionNames=new ArrayList<String>();//实体对象名称 @Override public Object getBean(String name) throws Exception { BeanDefinition beanDefinition=beanDefinitionMap.get(name); if(beanDefinition==null){ throw new IllegalArgumentException("No bean named"+name+" is defined"); } Object bean=beanDefinition.getBean(name); return bean; } //本质上就是进行名称和对象的映射到散列表上 public void registerBeanDefinition(String name,BeanDefinition beanDefinition) throws Exception{ beanDefinitionMap.put(name,beanDefinition); beanDefinitionNames.add(name); } }
BeanDefinition.java 传入实例【类似包装盒的作用-里面的东西可以千差万别】
package com.cnblogs.bean; /** * bean的内容及元数据,保存在BeanFactory中,包装bean的实体 */ public class BeanDefinition { private Object bean; private Class<?> beanClass; private String beanClassName; public BeanDefinition(){} public BeanDefinition(Object object){ this.bean=object; } public void setBeanClassName(String beanClassName) throws ClassNotFoundException { this.beanClassName=beanClassName; try{ this.beanClass=Class.forName(beanClassName); }catch(ClassNotFoundException e){ e.printStackTrace(); } } }
Client.java测试类
import com.cnblogs.Factory.AbstractBeanFactory; import com.cnblogs.Factory.BeanFactory; import com.cnblogs.bean.BeanDefinition; class HelloWorldServiceImpl { public void helloWorld2() { System.out.println("hello"); } } public class Client { public static void Step1() throws Exception{ BeanFactory beanFactory=new AbstractBeanFactory(); BeanDefinition beanDefinition=new BeanDefinition(new HelloWorldServiceImpl()); ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld",beanDefinition); HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld"); h.helloWorld2(); } public static void main(String[] args) throws Exception { Client.Step1(); } }
3.2 Step2【利用反射机制传入String 类名-实例化对象】
public static void Step2() throws Exception{ BeanFactory beanFactory=new AbstractBeanFactory();//无参构造,不传入实例 BeanDefinition beanDefinition=new BeanDefinition(); beanDefinition.setBeanClassName("com.spring.step1.test.HelloWorldServiceImpl"); ((AbstractBeanFactory) beanFactory).registerBeanDefinition("helloworld",beanDefinition); HelloWorldServiceImpl h=(HelloWorldServiceImpl) beanFactory.getBean("helloworld"); h.helloWorld2(); }
AbstractBeanFactory/getBean()方法
@Override public Object getBean(String name) throws Exception { BeanDefinition beanDefinition=beanDefinitionMap.get(name); if(beanDefinition==null){ throw new IllegalArgumentException("No bean named "+name+" is defined"); } Object bean=beanDefinition.getBean(); if (bean==null) { Constructor constructor=beanDefinition.getBeanClass().getDeclaredConstructor(); constructor.setAccessible(true);//设置权限 bean=constructor.newInstance(); beanDefinition.setBean(bean); } return bean; }
3.3 step3【注入参数】
之前的实体类HelloWorldServiceImpl中有属性后
private String text;
private int a;
HelloWorldServiceImpl实体类
class HelloWorldServiceImpl { private String text; private int a; public HelloWorldServiceImpl(){} public void helloWorld2(){ System.out.println("hello"); } public void helloWorld3() { System.out.println(text + a + " ss"); } }
PropertyValue封装类
package com.spring.step1.bean; /** * 用于bean的属性注入 * 和BeanDefinition一个效果,将实体进行封装到一个动态类中 */ public class PropertyValue { private final String name; private final Object value; // 省略get/set 后文对简单的get/set方法将直接省略 不再说明 public PropertyValue(String name, Object value) { this.name = name; this.value = value; } public String getName() { return name; } public Object getValue() { return value; } }
PropertyValues封装类
package com.spring.step1.bean; import java.util.ArrayList; import java.util.List; /** * 包装一个对象所有的PropertyValue。<br/> * 为什么封装而不是直接用List?因为可以封装一些操作。 * 单纯的一个ArrayList对象,其中封装了一些实体对象 */ public class PropertyValues { private final List<PropertyValue> propertyValueList = new ArrayList<PropertyValue>(); public PropertyValues(){} public void addPropertyValue(PropertyValue pv){ //TODO:这里可以对于重复propertyName进行判断,直接用list没法做到 // System.out.println(pv.getName()+pv.getValue()); this.propertyValueList.add(pv); } public List<PropertyValue> getPropertyValues() { return this.propertyValueList; } }
在BeanDefinition里加入【private PropertyValues propertyValues;】setter和getter默认
AbstractBeanFactory类中的getBean也要进行相关修改
@Override public Object getBean(String name) throws Exception { BeanDefinition beanDefinition=beanDefinitionMap.get(name); if(beanDefinition==null){ throw new IllegalArgumentException("No bean named "+name+" is defined"); } Object bean=beanDefinition.getBean(); if (bean==null) { Constructor constructor=beanDefinition.getBeanClass().getDeclaredConstructor(); constructor.setAccessible(true);//设置权限 bean=constructor.newInstance(); constructor.setAccessible(false);//设置权限 beanDefinition.setBean(bean); } creatBean(bean, beanDefinition); return bean; } public void creatBean(Object bean, BeanDefinition beanDefinition) throws Exception{ if(beanDefinition.getPropertyValues() != null) creatBeanWithProperty(bean, beanDefinition); } public void creatBeanWithProperty(Object bean, BeanDefinition beanDefinition) throws Exception{ int size =beanDefinition.getPropertyValues().getPropertyValues().size();//List长度 List<PropertyValue> list = beanDefinition.getPropertyValues().getPropertyValues();//由外及内 for (int i = 0; i <size ; i++) { if(list.get(i).getValue() instanceof BeanReference) { String beanName = ((BeanReference) list.get(i).getValue()).getName(); Object referenceBean = getBean(beanName); String ms = "set" + Character.toUpperCase(list.get(i).getName().charAt(0)) + list.get(i).getName().substring(1); Method m = bean.getClass().getDeclaredMethod(ms, referenceBean.getClass());//反射机制的数据配置-初始化处理 m.invoke(bean, referenceBean); }else {//手动进行赋值 String fieldName = list.get(i).getName(); Object value = list.get(i).getValue(); Field field = bean.getClass().getDeclaredField(fieldName); // getDeclaredField是获得所有的字段(不仅仅是public) field.setAccessible(true); // 这一步必须有 field.set(bean, value); field.setAccessible(false); // 这一步必须有 } } }
测试类step3
public static void Step3() throws Exception { // 1.初始化beanfactory BeanFactory beanFactory = new AbstractBeanFactory(); // 2.bean定义 BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setBeanClassName("com.spring.step1.test.HelloWorldServiceImpl"); // 3.设置属性 PropertyValues propertyValues = new PropertyValues(); propertyValues.addPropertyValue(new PropertyValue("text","Hello World!")); propertyValues.addPropertyValue(new PropertyValue("a",new Integer(15))); beanDefinition.setPropertyValues(propertyValues); // 4.注册bean ((AbstractBeanFactory)beanFactory).registerBeanDefinition("helloworld", beanDefinition); HelloWorldServiceImpl h = (HelloWorldServiceImpl) beanFactory.getBean("helloworld"); h.helloWorld3(); }
3.4 step4【加入引用变量】
引用实体类
package com.spring.step1.test; public class OutputService { public static void output(String text){ System.out.println(text); } }
加入引用变量
参考链接:
https://blog.csdn.net/it_man/article/details/4402245【这个讲的很清楚啊,举得例子和现实很贴切】