Spring有三大重要的组成,di依赖注入、ioc容器、aop切面编程。还有Spring bean执行流程也很重要。先从他的设计模式开始介绍他吧,他一共使用了9种设计模式。
首先他采用了工厂模式把以前硬编码的依赖通过beanFactory来注入依赖,由他解决bean之间的依赖问题,达到了松耦合的效果。他实现了FactoryBean接口的bean是一类叫做factory的bean。spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法并得到返回值。其实就是使用了一个容器把很多的东西放进去,使用的时候再拿出来。
刚才说使用的时候就在容器里拿出来,这个时候怎么拿就成了一个问题,Spring的依赖注入使用的Bean实例默认是单例的,他是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创建。下面是getSingleton()的过程图。
前面说过Spring MVC的执行流程,DispatcherServlet根据HandlerMapping返回的handler,向HandlerAdatper发起请求,处理Handler。HandlerAdapter根据规则找到对应的Handler并让其执行,执行完毕后Handler会向HandlerAdapter返回一个ModelAndView,最后由HandlerAdapter向DispatchServelet返回一个ModelAndView。简单的来说就是Spring定义了一个适配器,然后让这个适配器代替Controller执行相应的方法。
Spring会动态的给对象添加额外的职责,他的包装器在类上会有两种表现形式会实现这种动态,一个是Wrapper另一个是Decorator,后者比前者生成子类更加的灵活。
他其实就是aop的实现原理,他有两种表现形式,一个是动态代理,一个是静态代理。动态的话不需要手动编写代理类的,而静态需要手写,在我们每次写了切面,在织入切面的时候,aop容器会为目标对象创建动态的创建一个代理对象。这种的就是代理模式。
Spring是如何知道容器的,是如何知道Bean的等一系列操作的,他使用事件去监听去调用。而事件驱动的模式就是使用的观察者模式。常用的就是listener的实现。
Spring把外部资源对内部接口的访问,统一使用Resource接口,而Resource能够针对不同的底层资源,Spring将会提供不同的Resource实现类,不同的实现类负责不同的资源访问逻辑。简而言之就是Resource接口的实现类能够针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装。
这种模式最大的体现之处就是对外部资源的请求,以前如果我们对HTTP请求和响应的处理,可能会使用到HttpCLient或者其他的工具,而现在Spring给我们封装了一个RestRTemplate,不光对Http客户端的封装,还对JSON和对象的序列化和反序列化。除了Http,比如redis等,都可以使用这个Template这个远程调用的模版。他使用统一集中的方式来处理资源的获取和释放,能够减少代码的复用。
Spring其实是“一站式”的框架,他对三层都有自己的封装和解决方案,统一管理,让程序和框架之间低耦合。让程序员更轻松的完成业务。下面给出一张Spring完整的体系架构图。
IOC他是一个容器:heavy_plus_sign:控制反转,他把对象的创建权反转给Spring框架,使用的时候并从容器中取出。接下来我们模拟IOC的设计,第一步创建一个工厂,里面写入获取bean对象的工厂方法,从xml文件中解析bean,通过反射得到的对象存放到map中并解析xml;举个实例图。
第二步创建配置文件读取bean的信息,第三步当我们需要使用到不同实现类中的方法时候,我们只需要修改Beans.xml配置文件里面实现类的class文件位置即可。最后我们使用一下IOC,第一步创建maven项目,导入Spring ioc依赖的jar包;第二步创建一个接口和实现类;第三步创建Spring的核心配置文件-applicationContext.xml,并引入约束到这个文件,官网可以下载这个约束,引入的约束如下图所示
第四步在配置文件里配置实现类,最后测试!
Spring的工厂提供了两个对外的接口,一个是ApplicationContext,另一个是BeanFactory。ApplicationContext有两个实现类,一个ClassPathXmlApplicationContext加载类路径下的Spring配置文件,另一个FileSystemXmlApplicationContext加载本地磁盘下的Spring配置文件。而BeanFactory他是Spring框架早期的创建Bean对象的工厂接口,他跟ApplicationContext的区别就是他采用了延迟加载,第一次getBean的时候,才会初始化这个Bean,而ApplicationContext在加载applicationContext.xml时候就会创建具体的Bean对象的实例。
在配置文件中配置具体的实现类的时候,一般会使用id和class属性,前者是bean的唯一标示,后者是他在项目里的全路径名。还有scope属性,他代表Bean的作用范围;init-method属性,能够当bean被加载到容器的时候,调用init-method属性指定的方法;destroy-method属性,当bean从容器中删除的时候调用destroy-method属性指定的方法。
第一种是无参构造,Spring默认调用的就是无参构造方法实力化bean;第二种是静态工厂实例化,构造工厂静态方法,配置这个实现类的时候,class属性写的是工厂类的全路径名;第三种是实例工厂实例化的方法,构造工厂实例方法,配置工厂bean的id和实例化工厂方法的名字。
DI是在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!他有很多种方法的注入,下面我会一一介绍。第一种构造方法的注入,就是利用bean的构造方法对bean属性的赋值。创建一个实体类并序列化,然后把这个实体类配置到配置文件里即可,如下实例图;
第二种set方法注入,利用bean属性里的set方法对属性赋值,前面步骤跟第一种一样,不同的是在配置文件里面,普通属性用value指定值,对象属性用ref指定需要注入的bean的id。如下实例图,
还有p命名空间的写法p:简单属性名=“值”,如下实例图,
和SpEL的写法,使用#{}来注入,如下实例图;
第三种数组或者list注入,区别在于配置文件的注入,如下实例图;
第四种Set集合的注入,修改的地方如下实例图,
注意的地方是spring在注入set的时,给我们注入的是一个LinkedHashSet,所以在输入set集合中的元素时,是按照我们注入的顺序来的,并不是无序的;第五种Map集合的注入,修改实体类,添加一个Map类型的属性,并提供set方法。配置文件的注入如下实例图;
第六种Properties的注入,修改实体类,添加一个Properties类型的属性,并提供set方法。配置文件的注入如下实例图;
当越来越多的bean注入的时候,如果把所有的bean都配置在applicationContext.xml中,applicationContext.xml就会变得很庞大,不便于修改与维护,可以把spring的配置文件进行分离。分离的话,有两种方法,第一种采用主从的思想,先写两个配置文件,一个当成总的配置文件,只有一些大概的内容,另一个文件放具体的内容,只要加载总配置文件,这两个配置文件都可加载;第二种采用集群的思想,当实例化ApplicationContext的时候,指定多个文件。下图是以上的学习总结示意图。
因为注解的配置简单,维护方便,所以我们接下来引入注解对Spring项目进行开发,首先说一下Spring对jdbc的整合,导入jdbc的依赖之后,我们只需要在配置文件中把jdbc当成一个bean注入到需要使用的层,然后使用Spring的模版控制器Template,JdbcTemplate就可以使用了!到了后面使用Spring boot的时候开箱即用,直接导入依赖,加上注解就可以使用了。然后说一下IOC涉及到注解,第一个关于Bean对象的注解,@Component @Controller @Service @Repository,配置创建到销毁;第二个用于注入值的注解,@Value @Autowired @Qualifier @Resource;第三个与生命周期相关的注解,@PostConstruct @PreDestroy;第四个与作用范围相关的注解,@Scope;第五个与全注解相关的注解,@Configuration、@ComponentScan、@Bean、@Import、@PropertySource。最后就是Spring整合了junit的注解,首先引入依赖,然后在单元测试类上加@RunWith、@ContextConfuguration注解,最后在单元测试类中声明测试目标,加上@Autowired即可。下面是关于注解开发这个学习的示意图。
AOP是一个切面编程,横向抽取的机制对在不修改原对象代码的情况下,通过通过代理对象,调用增强功能的代码,从而对原有业务方法进行增强!他有两种实现方式,一个是JDK动态代理,对目标类进行代理,另一个是Cglib动态代理,是对目标类的子类进行代理。AOP使用中会有以下这些构成:第一个连接点,指那些被拦截的点;第二个是切入点,是指我们要对哪些连接点进行拦截;第三个是通知,指拦截到连接点之后要做的事情,分为前置通知、后置通知、异常通知、最终通知和环绕通知;第四个就是引介,在一种特殊的通知在不修改代码的前提下,对运行期动态添加一些方法;第五个是目标对象,也就是代理的对象;第六个是织入,是指把增强应用到目标对象来创建新的代理对象的过程;第七个是代理,一个被AOP织入增强后产生的结果代理类;第八个切面,切入点和通知的结合。最后就可以用一些注解,写一个切面了!下面是AOP总结的图。
使用JdbcTemplate进行增删改查,下面给出实例图展示,实现update方法。
实现delete方法
实现条件查询方法
实现全部查询方法
除了以上这种在DAO层声明JdbcTemplate方法外,还可以直接继承JdbcDaoSupport。首先在DAO层的实现类上继承JdbcDaoSupport,然后使用this.getJdbcTemplate()即可,最后在配置文件的时候不需要在配置JdbcTemplate,而是注入DataSource。
我们首先配置xml形式的事务,可以看到具体的操作。 第一步我们要配置事务管理器,在配置文件中加上DataSourceTransactionManager;如图。
第二步配置事务的属性;如图。
第三步配置事务切面;如图。
如果我们采用注解的声明事务控制的话,第一步在配置文件中开启Spring对注解的支持;如图。
第二步在相关的类上加入注解,因为采用注解配置,所以我们不能继承dbcDaoSupport,只能在DAO中声明JdbcTemplate属性;最后测试。