标签:设置 移动设备 初始 version 模块 world 编译器 简化 cer
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring中的IOC思想:
(1)IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即 应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
(2)最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法的。
(3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
Spring中的IOC容器:
Spring 提供了以下两种不同类型的容器,分别为BeanFactory和ApplicationContext。
BeanFactory:这是一个最简单的容器,它主要的功能是为依赖注入 (DI) 提供支持.在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。
BeanFactory factory = new XMLBeanFactory(new FileInputSteam("mybean.xml"));
MyBean mybean = (MyBean) factory.getBean("mybean");
Mybean.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
ApplicationContext:Application Context 是 BeanFactory 的子接口,也被成为 Spring 上下文。 Application Context 是 spring 中较高级的容器。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。 另外,它增加了企业所需要的功能,比如,从属性文件中解析文本信息和将事件传递给所指定的监听器。ApplicationContext 包含 BeanFactory 所有的功能,一般情况下,相对于 BeanFactory,ApplicationContext 会更加优秀。当然,BeanFactory 仍可以在轻量级应用中使用,比如移动设备或者基于 applet 的应用程序。
最常被使用的 ApplicationContext 接口实现有两种:
FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径。
ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
ApplicationContext context = new FileSystemXmlApplicationContext
(fullPathofXMLfile);
MyBean mybean = (MyBean) factory.getBean("mybean");
.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name=" " value=" "/>
</bean>
</beans>
BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
(1)BeanFactory:是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
①继承MessageSource,因此支持国际化。
②统一的资源文件访问方式。
③提供在监听器中注册bean的事件。
④同时加载多个配置文件。
⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。
③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。
(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
Spring中的Bean
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的,例如,已经在先前章节看到的,在 XML 的表单中的 定义。
bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:
1.如何创建一个 bean
2.bean 的生命周期的详细信息
3.bean 的依赖关系
Bean 与 Spring 容器的关系如下所示:
Spring 配置元数据
Spring IoC 容器完全由实际编写的配置元数据的格式解耦。有下面三个重要的方法把配置元数据提供给 Spring 容器:
1.基于 XML 的配置文件
2.基于注解的配置
3.基于 Java 的配置
Spring容器中的bean可以分为5个范围:
(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护;
(2)prototype:为每一个bean请求提供一个实例;
(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收;
(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效;
(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
可以在 bean 的配置文件中设置作用域的属性,如
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton/protype…">
<!-- collaborators and configuration for this bean go here -->
</bean>
Spring Bean的生命周期:
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
(3)处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor:如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
(5)InitializingBean 与 init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(7)DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(8)destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"">
<bean id="..." class="..." init-method="init" destroy-method="destroy" >
<!-- collaborators and configuration for this bean go here -->
</bean>
</beans>
Bean 定义继承
Bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。
子 Bean的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。
Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 Bean的定义作为模板和其他子 Bean就可以从父 Bean中继承所需的配置。
当你使用基于 XML 的配置元数据时,通过使用父属性,指定父 Bean作为该属性的值来表明子 Bean的定义。
如:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
</bean>
<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
<property name="message1" value="Hello India!"/>
<property name="message3" value="Namaste India!"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="beanTeamplate" abstract="true">
<property name="message1" value="Hello World!"/>
<property name="message2" value="Hello Second World!"/>
<property name="message3" value="Namaste India!"/>
</bean>
<bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
<property name="message1" value="Hello India!"/>
<property name="message3" value="Namaste India!"/>
</bean>
</beans>
Spring的AOP理解:
OOP面向对象,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理。
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
JDK动态代理:
JDK动态代理技术首先要求我们目标对象需要实现一个接口:
public interface IHello {
void sayHello(String str);
}
接下来就是我们需要代理的真实对象,即目标对象:
public class Hello implements IHello {
@Override
public void sayHello(String str) {
System.out.println("hello "+str);
}
}
这是一个真实的对象,我们希望在不更改原有代码逻辑的基础上增强该类的sayHello方法,利用JDK动态代理技术需要我们实现InvocationHandler接口中的invoke方法:
public class DynamicProxyHello implements InvocationHandler {
//目标对象
private Object target;
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
System.out.println("调用前");
//执行要处理对象的原本方法
result= method.invoke(this.target, args);
System.out.println("调用后");
return result;
}
}
在invoke方法中可以看到,在调用目标对象的方法前后我们对方法进行了增加,这其实就是AOP中Before和After通知的奥义所在。
接下来进行测试:
public class DynamicProxyTest {
public static void main(String[] args) {
IHello iHello=(IHello) new DynamicProxyHello().bind(new Hello());
iHello.sayHello(" dynamic");
IHello iHello=new Hello();
iHello.sayHello(" 明天");
//查看iHello对象的类型
System.out.println(iHello.getClass().getName());
}
}
最后控制台显示:
调用前
hello 明天
调用后
可以看到和AOP几乎一样,前面提到过,动态代理就是AOP的核心。同时我们可以看到被代理的类的类型是:com.sun.proxy.$Proxy0。这个类是在Run-Time(运行时)生成的,也就是说,JDK动态代理中代理类的生成来自于Java反射机制的支撑。
CGLib动态代理技术
CGLib动态代理技术不需要目标对象实现自一个接口,且类也不能使用final来修饰。
先写一个目标类
public class HelloService {
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
再写一个代理类:
public class ProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置。。。");
Object o1=methodProxy.invokeSuper(o,objects);
System.out.println("后置。。。");
return o1;
}
}
再写一个测试类:
public class Test {
public static void main(String[] args) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(HelloService.class);
enhancer.setCallback(new ProxyInterceptor());
HelloService helloService=(HelloService) enhancer.create();
helloService.sayHello();
System.out.println(helloService.getClass().getName());
}
}
控制台显示:
HelloService构造器
前置。。。
HelloService:sayHello
后置。。。
com.cglib.HelloService$$EnhancerByCGLIB$$64428683
JDK和CGLIB动态代理区别:
1. 何时使用JDK还是CGLIB?
1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
2)如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
3)如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB之间转换。
2. JDK动态代理和CGLIB动态代理的原理区别
1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成final, 对于final类或方法,是无法继承的。
3. Spring如何选择用JDK还是CGLIB?
1)当Bean实现接口时,Spring就会用JDK的动态代理。
2)当Bean没有实现接口时,Spring使用CGlib是实现。
3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。
标签:设置 移动设备 初始 version 模块 world 编译器 简化 cer
原文地址:https://www.cnblogs.com/reecelin/p/11922293.html