Spring IOC容器接口设计
今天小编给各位分享capable的知识,文中也会对其通过Spring IOC容器接口设计和java编程,spring里ioc和aop用什么原理实现的等多篇文章进行知识讲解,如果文章内容对您有帮助,别忘了关注本站,现在进入正文!
内容导航:
一、Spring IOC容器接口设计
Spring IoC容器的设计是分析Spring源码必不可少的一步。接口定义了各个组件之间的宏观关系,实现类则在实际层面上达成接口的功能。如果把整个IoC当做一个人体的话,接口就是骨骼,撑起了其整体架构,实现类是其血肉,使之丰满活动起来。
下面就来看看IoC接口设计图
第一条设计主线是:从接口BeanFactory到HierarchicalBeanFactory再到ConfigurableBeanFactory是一条设计路径。BeanFactory定义了IoC容器的最基础规范,包含了getBean(),containBean(),getType(),getAlias()等IoC容器的基本方法,而HierarchicalBeanFactory在继承了BeanFactory之后,添加了getParentBeanFactory方法,使BeanFactory具备了父容器管理功能,拥有了父子结构。而在接下来的ConfigurableBeanFactory主要定义了一些BeanFactory的配置功能,例如setParentBeanFactory()设置父容器,addBeanPostProcessor()配置Bean后置处理器,registerCustomEditor()配置自定义属性编辑器等。第二条设计主线是:以ApplicationContext应用上下文为核心的接口设计。从BeanFacotry到ListableBeanFactory再到ApplicationContext,再到ConfigurableApplicationContext。我们常用的应用上下文实例:ClassPathXmlApplicationContext,FileSystemXmlApplicationContext等都是ConfigurableApplicationContext的实现类。在ListabelBeanFactory接口中细化了BeanFactory的许多功能,例如:getBeanDefinitionNames获取工厂中定义的所有bean名称,containsBeanDefinition,getBeanDefinitionCount(),findAnnotationOnBean()等Bean解析方面的功能。另外ApplicationContext通过继承ApplicationEventPublisher拥有了发布应用上下文事件的能力,继承MessaegeSource拥有了处理国际化信息的能力,继承ResourceLoader可以以多种方式处理资源文件,继承LifeCycle拥有了生命周期管理的功能。 BeanFactory是IoC容器的基本规范,但它只拥有一些基本功能,空有骨骼,没有血肉,还无法应用于实际。ApplicationContext则在BeanFactory基础上赋予了更多实际中需要的高级特性。第三条设计主线是:BeanFactory到AutowireCapableBeanFactory再到ConfigurableListableBeanFactory接口。AutowireCapableBeanFactor这个接口很少在程序代码中使用,,它的功能主要是为了装配applicationContext管理之外的Bean。整合其他框架是这个接口的优势所在,它可以连接和填充那些生命周期不被Spring管理的已存在的bean实例。通过ApplicationContext的getAutowireCapableBeanFactory方法就很容易访问此接口.一、java编程,spring里ioc和aop用什么原理实现的
控制反转(IOC)(理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”)
1、Ioc—Inversion of Control:即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
2、谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象即由Ioc容器来控制对象的创建。
谁控制谁?当然是IoC 容器控制了对象。
控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
3、为何是反转,哪些方面反转了: 有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象。
为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转。
哪些方面反转了?依赖对象的获取被反转了。
还是不明白没事,下面搞个简单案例来说就懂啦 !!!
例子:当我们在任何一个有实际开发意义的程序项目中,我们会使用很多类来描述他们特有的功能,并且通过类与类之间的相互协作来完成特定的业务逻辑。这个时候,每个类都需要负责管理与自己有交互的类的引用和依赖,代码将会变的异常难以维护和极高的高耦合。而IOC的出现正是用来解决这个问题,我们通过IOC将这些依赖对象的创建、协调工作交给spring容器去处理,每个对象值需要关注其自身的业务逻辑关系就可以了。在这样的角度上来看,获得依赖的对象的方式,进行了反转,变成了由spring容器控制对象如何获取外部资源(包括其他对象和文件资料等)。
总的来说:IOC就是通过在Xml配置文件里依赖注入来解决代码问题。
IOC的注入类型有几种?主要可以划分为三种:构造函数注入、属性注入和接口注入。Spring支持构造函数注入和属性注入
面向切面(AOP)
(面向切面编程,AOP其实只是OOP的补充而已,AOP基本上是通过代理机制实现的。)
我们管切入到指定类指定方法的代码片段称为切面,而切入到哪些类、哪些方法则叫切入点。有了AOP,我们就可以把几个类共有的代码,抽取到一个切片中,等到需要时再切入对象中去,从而改变其原有的行为。
我们都知道 Java 是 OOP-面向对象编程的,它有自己的优势,也有自己的不足。比如说:在我们开发中,都会有一条业务主线(即客户的需求)。而我们要做的就是实现这个主线上的需求。我们在实现这些功能的时候,经常要干一些额外的不可避免的事情,比如事务的管理,日志的记录等,就很繁杂且代码量增多,所以 Spring 提供了另一种角度来思考程序结构,也就是把这一些事情剥离出来,然后适时适地的把它们加入到我们的代码中,比如说 声明式事务管理的时候,我们在 service 层检测到save*、update*这些方法要被调用的时候,我们先进行开启事务什么的,这就是AOP,面向编程的思想。
AOP的术语:
1、通知(Advice):就是你想要的功能,也就是上面说的 安全,事物,日志等。你给先定义好把,然后在想用的地方用一下
2、连接点(JoinPoint):这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点.其他如aspectJ还可以让你在构造器或属性注入时都行,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。
3、切入点(Pointcut):上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对把,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说),你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
4、切面(Aspect):切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的before,after,around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
5、引入(introduction):允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗
6、目标(target):引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。
7、代理(proxy):怎么实现整套aop机制的,都是通过代理,这个一会给细说。
8、织入(weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时,为什么是运行时,后面解释。
二、快速切入:Spring框架核心概念总览
简而言之,Spring是企业级Java的开源开发框架。Spring框架的核心功能可用于开发任何java应用程序。Spring框架的核心模块如下:
任何由 Spring IoC 容器初始化的普通 Java 类都称为 Spring Bean。我们使用 spring 应用程序上下文来获取 Spring Bean 实例。 Spring IoC Container 管理 Spring Bean 范围/作用域的生命周期并在 bean 中注入任何所需的依赖项。
Spring bean的不同作用域:
对于任何 Java 应用程序,都有两个不同的作用域,称为单例(Singleton)和原型(Prototype)
主要有三种不同的作用域(或范围),即 请求(request)、会话(session)和全局会话(global-session) ,专门针对基于 Spring 的 Java Web 应用程序。
Singleton 是任何 bean 的默认作用域。这意味着每个 IoC 容器将创建单个 bean 实例。因此,单例 bean 不是线程安全的。
要设置 spring bean 的范围,我们可以在 标签中使用scope属性。 @scope 用于基于注释的 DI。
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理它们从创建到销毁的完整生命周期。 Spring 容器使用依赖注入 (DI) 来管理组成应用程序的组件。
有两种不同类型的容器:
BeanFactory 容器 :这是 Spring 容器的核心。 org.springframework.beans.factory.BeanFactory 是一个接口,充当 IoC 容器,它实例化、配置和管理许多 bean。应用示例如下:
ApplicationContext 容器 :org.springframework.context.ApplicationContext 接口也充当 IoC 容器,但 ApplicationContext 接口建立在 BeanFactory 接口之上,以提供一些BeanFactory 额外的功能,例如与 Spring 的 AOP 的简单集成、消息资源处理(对于 I18N )、事件传播、Web 应用程序的应用层特定上下文(例如 WebApplicationContext)。所以使用 ApplicationContext 比使用 BeanFactory更好些。示例代码如下:
对于基于注解的依赖注入,使用@Autowired 注解。标有@Component/@Service/@Repository 等的类可以注入到标有@Autowired 的属性中
@Autowired 应用于:
1)基于构造器和setter的区别
2)context:annotation-config 和 context:component-scan 的区别
3)@Component、@Controller、@Repository & @Service 注解的区别
如果一个类用@Component/@Controller/@Service/@Repository 注解标记,那么Spring DI 容器可以在组件扫描机制期间识别该类。但是,对于服务层类使用@Service 是个好主意,并且@Controller 应该在spring mvc web 控制器中使用。 @Repository 用于将 DAO 导入 DI 容器。此外,任何未经检查的异常都将被转换为 Spring DataAccessException。
4)ViewResolver 与 MultipartResolver
ViewResolver 用于按名称解析视图。该接口由 InternalResourceViewResolver 实现 ;
MultipartResolver 用于处理 web 应用程序中的文件上传。
5)Spring MVC 中的验证
org.springframework.validation.Validator 接口支持 spring MVC 验证。验证表单的一些实用方法是 ValidationUtils 类中的 rejectIfEmptyOrWhitespace() 和 rejectIfEmpty()。示例如下:
Spring MVC 中验证表单的另一种方法是:
HandlerInterceptor 接口充当 spring MVC 拦截器。它在服务请求之前和之后拦截。如果您实现了 HandlerInterceptor 接口,则 preHandle()、postHandle() 和 afterCompletion() 是要覆盖的方法。但是,为了避免覆盖,您可以使用 HandlerInterceptorAdapter 类。
实现 ServletContextAware 和 ServletConfigAware 接口并覆盖以下方法:
数据库事务是一组被视为关联工作单元的操作。事务的主要原则是提交所有操作或在失败的情况下回滚所有操作。在交易中提交数据时,我们需要确保交易协议/称为 ACID(原子性-一致性-隔离-持久性)的属性:
全局事务 vs 本地事务:
脏读、幻读和不可重复读:
隔离与传播:
在旧版本的 spring 和 hibernate 集成中,需要 HibernateDAOSupport 和 HibernateTemplate。但是,较新版本的 Spring 不建议使用这两个类(这里仅做了解)。
通常我们从 HibernateDAOSupport 扩展我们的 DAO 类,并且 getHibernateTemplate() 方法将可用于Hibernate会话中的 CRUD 操作。由于这不是推荐的方法,所以我们在 DAO 中注入会话工厂(SessionFactory)。下面的代码片段会给你一些关于 HibernateDAOSupport 和 HibernateTemplate 的想法:
DAO 是一种设计模式,以最大限度地减少应用程序和后端之间的耦合;
ORM 处理如何将对象映射到对象关系数据库中,从而减少数据库和应用程序之间的耦合。
如果您在没有 DAO 的情况下使用 ORM,那么您的应用程序将变得依赖于 ORM,因此很难从一个 ORM(例如Hibernate)移动到另一个 ORM(例如 NoSQL)。
Spring DAO 是使用@Repository 注解实现的。 Spring 存储库扩展 JPARepository 并传递 JPA 实体及其主键。
最后,关于Spring框架相关的概念就简要介绍到这里,希望这能给你进入并深入Spring技术栈一个简单入口,而不会被Spring技术生态所惊吓(Spring现在都成软件开发技术的全家桶了,啥都有)——日进一步,锲而不舍,终将大成!
三、spring后置处理器接口有哪些
Spring中bean工厂后置处理器(BeanFactoryPostProcessor)使用激情的狼王
简书作者
0.2882017-11-24 11:00打开App
Spring中bean工厂后置处理器也就是BeanFactoryPostProcessor接口,是用来干什么的呢?我们都知道一个好的框架必备的特性至少得有开闭原则,可扩展性。
在前面的文章里SpringIOC源码阅读—BeanDefinitionDocumentReader我们了解到Spring对bean定义的载入有很多种方式,读取的过程是可插拔的,不论何种形式,spring的IOC容器只要获得了bean定义信息,都可以正常工作。而我们熟知的配置读取方式就是XML文件,如果你希望,可以自己定制配置信息的读取过程,这就是Spring的特性体现之一。
同样BeanFactoryPostProcessor也是Spring可扩展性的一个体现,我们读一下这个接口的源码
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
注释的意思是允许我们在工厂里所有的bean被加载进来后但是还没初始化前,对所有bean的属性进行修改也可以add属性值。
下面通过实例看下效果
beans.xml
我们定义一个普通bean和一个BeanFactroy后置处理器
User类
package xz.quartz.analysis;
public class User {
String name;
String age;
public User() {
System.out.println("construtor");
System.out.println("name:"+name+",age:"+age);
}
public void go(){
System.out.println("age:"+age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
BeanFactroy后置处理器类
package xz.quartz.analysis;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class beanfactorypostpro implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("******调用BeanFactoryPostProcessor开始");
//获取到Spring中所有的beanName
String[] beanStr = beanFactory.getBeanDefinitionNames();
//循环bean做出自定义的操作
for (String beanName : beanStr) {
System.out.println("bean name:"+beanName);
if ("user".equals(beanName)) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
System.out.println("修改user的age值");
beanDefinition.getPropertyValues().add("age", "20");
}
}
System.out.println("******调用BeanFactoryPostProcessor结束");
}
}
在上面BeanFactoryPostProcessor的实现类里通过我写的注释可以看到这个工厂后置器获取到所有的beanName,并且可以对特定的bean或者全部bean进行操作,这也就是后置器的核心所在之处。
main方法
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
System.out.println("获取到User实例 ");
((User)applicationContext.getBean("user")).go();
}
主函数中第一行初始化的时候,读取beans.xml时,会获取实现了BeanFactoryPostProcessor接口的bean,然后把它作为后置处理器类来处理。
然后我们通过调用user的go方法,输出age的值来看下
******调用BeanFactoryPostProcessor开始
bean name:user
修改user的age值
bean name:beanfactorypostpro
******调用BeanFactoryPostProcessor结束
construtor
name:null,age:null
获取到User实例
age:20
我们在BeanFactroy后置处理器类里给user的age属性成功赋值成20,大家通过程序实例可以看到后置处理器的作用和用法了。
在这里提出两个疑问
1.后置处理器和bean指定的init-method还有构造方法的顺序是谁先谁后呢?
2.这三个方法同时对属性赋值,最终会是哪个起作用呢?
对上面的两个问题,我们改造下代码,先把构造方法加上赋值过程
User类
package xz.quartz.analysis;
public class User {
String name;
String age;
void init(){
System.out.println("init");
}
public User() {
System.out.println("construtor");
name = "zx-construtor";
age = "zx-construtor";
System.out.println("name:"+name+",age:"+age);
}
public void go(){
System.out.println("最终age的值:"+age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
输出结果:
******调用BeanFactoryPostProcessor开始
bean name:user
修改user的age值
bean name:beanfactorypostpro
******调用BeanFactoryPostProcessor结束
construtor
name:zx-construtor,age:zx-construtor
init
name:zx-construtor,age:20
获取到User实例
最终age的值:20
可以看到程序先执行后置器将值改为20,然后执行的构造方法,改为zx-construtor,但是最终age的值为20,到好文
关于capable的问题,通过《快速切入:Spring框架核心概念总览》、《spring后置处理器接口有哪些》等文章的解答希望已经帮助到您了!如您想了解更多关于capable的相关信息,请到本站进行查找!
爱资源吧版权声明:以上文中内容来自网络,如有侵权请联系删除,谢谢。