Spring反射机制
Spring是分层的Java SE/EE应⽤⼀站式的轻量级开源框架,以IoC(Inverse of Control)和AOP(Aspect Oriented Programming)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应⽤技术,此外,Spring整合了开源世界⾥众多的第三⽅框架和类库。
Spring的体系结构:
Spring整个框架按其所属功能可划分为5个主要模块:数据访问和集成、Web及远程操作、测试框架、AOP和IoC。
IoC:Spring的核⼼模块实现了IoC的功能,它将类和类之间的依赖从代码中脱离出来,⽤配置的⽅式进⾏依赖关系描述,由IoC容器负责依赖类之间的创建、拼接、管理、获取等⼯作。BeanFactory接⼝是Spring框架的核⼼接⼝,它实现了容器许多核⼼的功能。Context模块构建于核⼼模块之上,扩展了BeanFactory的功能,添加了i18n国际化、Bean⽣命周期控制、框架事件体系、资源加载透明化等多项功能。此外,该模块还提供了许多企业级服务的⽀持。ApplicationContext是Context模块的核⼼接⼝。表达式语⾔模块是统⼀表达式语⾔的⼀个扩展,该表达式语⾔⽤于查询和管理运⾏期的对象,⽀持设置或获取对象属性,调⽤对象⽅法、操作数组、集合等。还提供了逻辑表达式运算、变量定义等功能。使⽤它可以⽅便地通过表达式串和Spring IoC容器进⾏交互。
AOP模块:AOP是进⾏横切逻辑编程的思想,开拓了⼈们考虑问题的思路。在AOP模块⾥,Spring提供了满⾜AOP Alliance规范的实现,此外,还整合了AspectJ这种AOP语⾔级的框架。Java 5.0引⼊java.lang.instrument,允许在JVM启动时启⽤⼀个代理类,通过该代理类在运⾏期修改类的字节码,改变⼀个类的功能,实现AOP的功能。
数据访问和集成:Spring站在DAO的抽象层⾯,建⽴了⼀套DAO层统⼀的异常体系,同时将各种访问数据的检查型异常转换成⾮检查型异常,为整个各种持久层框架提供基础。其次,Spring通过模版化技术对各种数据访问技术进⾏了薄层的封装,将模式化的代码隐藏起来,使数据访问的程序得到了⼤幅简化。
Web及远程调⽤:该模块建⽴在ApplicationContext模块之上,提供了Web应⽤的各种⼯具类,若通过Listener或Servlet初始化Spring容器,将Spring容器注册到Web容器中。其次,该模块还提供了多项⾯向Web的功能。此外,Spring还可以整合Struts、WebWork、Tapestry Web 等MVC框架。
Spring注解:
在ApplicationContext⽂件中,使⽤Spring的<context:component-scan base-package="">扫描指定类包下的所有类,这样在类中定的Spring 注解才能产⽣作⽤。
@Repository:定义⼀个DAO Bean
@Autowired:将Spring容器中的Bean注⼊进来
@Service:将⼀个类标注为⼀个服务层的Bean
@ContextConfiguration:指定Spring的配置容器
@Controller:将⼀个类标注为Spring MVC的Controller
@RequestMapping(value="/index.html"):负责处理⼀个xxx.html请求
IoC
DI(Dependency Injection):让调⽤类的某⼀接⼝实现类的依赖关系由第三⽅(容器或协作类)注⼊,以移出调⽤类对某⼀接⼝实现类的的依赖。
从注⼊⽅法上来看,主要可以划分为3种类型:构造函数注⼊、属性注⼊和接⼝注⼊。Spring⽀持构造函数注⼊和属性注⼊。
构造函数注⼊:在构造函数注⼊中,我们通过调⽤类的构造函数,将接⼝实现类通过构造函数变量传⼊。
属性注⼊:属性注⼊可以有选择地通过Setter⽅法完成调⽤类所需依赖的注⼊。
接⼝注⼊:将调⽤累所有依赖注⼊的⽅法抽取到⼀个接⼝中,调⽤类通过实现该接⼝提供相应的注⼊⽅法。
java的反射机制
Java语⾔允许通过程序化的⽅式间接对Class的对象实例操作,Class⽂件由类装载器装载后,在JVM中将形成⼀份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:构造函数、属性和⽅法等。Java允许⽤户借由这个Class相关的元信息对象间接调⽤Class对象的功能.
例:
public Class Car{
private String brand;
private String color;
private int maxSpeed;
public Car(){}
public Car(String brand,String color,int maxSpeed){
this.brand = brand;
this.maxSpeed = maxSpeed;
}
public void introduce(){
System.out.println("brand"+brand+",color"+color+",+maxSpeed"+maxSpeed);
}
...
}
import flect.Construcor;
import flect.Field;
import flect.Method;
public class ReflectTest{
public static Car initByDefaultConst() throws Throwable{
//通过类加载器获取Car类对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = loader.loadClass(Car):
//获取类的默认构造器对象并通过它实例化Car
Constructor cons = DeclardConstructor((Class[])null);
Car car = (wInstance():
/
/通过反射⽅法设置属性
Method setBrand = Method("setBrand",String.class);
setBrand.invoke(car,"WCA72");
Method setColor = Method("setColor ",String.class);
setColor .invoke(car,"black");
Method setMaxSpeed = Method("setMaxSpeed ",int.class);
setMaxSpeed .invoke(car,200);
return car;
}
public static void main(String[] args) throws Throwable{
Car car = initByDefaultConst();
car.introduce();
}
}
类装载器ClassLoader
⼯作机制:
类装载器就是寻类的字节码⽂件并构造出类在JVM内部表⽰的对象组件。在Java中,类装载器装⼊JVM中,要经过以下步骤:
1.装载:查和导⼊Class⽂件
2.链接:执⾏校验、准备和解析步骤,其中解析步骤是可以选择的:
校验:检查载⼊Class⽂件数据的正确性
准备:给类的静态变量分配存储空间
解析:将符号引⽤转成直接引⽤
3.初始化:对类的静态变量、静态代码块执⾏初始化⼯作
类加载器⼯作由ClassLoader及其⼦类负责,ClassLoader是⼀个重要的Java运⾏时系统组件,它负责在运⾏时查和装⼊Class字节码⽂件。JVM在运⾏时会产⽣三个ClassLoadre:根装载器、ExtClassLoader和AppClassLoader。根装载器不是ClassLoader的⼦类,负责装载JRE的核⼼类库。ExtClassLoader和AppClassLoader都是ClassLoader的⼦类。其中,EctClassLoader负责装载JRE扩展⽬录ext中的JAR 类包,AppClassLoader负责装载Classpath路径下的类包。
JVM装载类时使⽤“全盘负责委托机制”,“全盘负责”是指当⼀个ClassLoader装载⼀个类时,除⾮显式地使⽤另⼀个ClassLoader,该类所依赖及引⽤的类也由这个ClassLoader载⼊:“委托机制”是指先委托⽗装载器寻⽬标类,只有在不到的情况下才从⾃⼰的类路径中查并装载⽬标类。
ClassLoader的重要⽅法:
Class loadClass(String name):name参数指定类装载器需要装载类的名字,必须使⽤全限定类名。该⽅法有⼀个重载⽅法loadClass(String name,boolean resolve),resolve参数告诉类装载器是否需要解析该类。在初始化类之前,应考虑进⾏类解析的⼯作,但并不是所有的类都需要解析,若JVM值需知道该类是否存在或出该类的超类,那么就不需要进⾏解析。
Class defineClass(String name,byte[] b,int off,int len):将类⽂件的字节数组转换成JVM内部的java.lang.Class对象。字节数组可以从本地⽂件系统、远程⽹络获取。name为字节数组对应的全限定类名。
Class findSystemClass(String name):从本地⽂件系统载⼊Class⽂件,若本地⽂件系统更不存在该Class⽂件,将抛出ClassNotFoundException异常。
Class findLoadedClass():调⽤该⽅法来查看ClassLoader是否已装⼊某个类。若已装⼊,则返回java.lang.Class对象,否则返回null。ClassLoader getParent():获取类装载器的⽗装载器。
反射对象类在flect包中定义,下⾯是最主要的三个反射类:springmvc选择题
Constructor:类的构造函数反射类,通过Class#getContructors()⽅法可以获得类的所有构造函数反射对象数组。在JDK 5.0中,还可以通过getContructor(Class parameterTypes)获取拥有特定⼊参的构造函数反射对象。Constructor的⼀个主要⽅法是newInstance(Object[] initargs),通过该⽅法可以创建⼀个对象类的实例,相当于new关键字。
Method:类⽅法的反射类,通过Class#getDeclaredMehtods()⽅法可以获取类的所有⽅法反射类对象数组Method[]。在 JDK 5.0中可以通过getDeclaredMehtods(String name,Class parameterTypes)获取特定
签名的⽅法,name为⽅法名;Class为⽅法⼊参类型列表。Method最主要的⽅法是invoke(Object obj,Object[] args),obj表⽰操作的⽬标对象,args为⽅法⼊参。
Method还有很多⽤于获取类⽅法更多信息的⽅法:
Class getReturnType():获取⽅法的返回值类型
Class[] getParameterTypes():获取⽅法的⼊参类型数组
Class[] getExceptionTypes():获取⽅法的⼀场类型数组
Annotationp[][] getParamerterAnnotations():获取⽅法的注解信息
Field:类的成员变量的反射类,通过Class#getDeclaredFields()⽅法可以获取类的成员变量反射对象数组,通过
Class#getDeclaredFields(String name)则可获取某个特定名称的成员变量反射对象。Field类最主要的⽅法是set(Object obj,Object value),obj表⽰操作⽬标评对象,通过value为⽬标对象的成员变量设置值。若成员变为为基础类型,⽤户可以使⽤Field类中提供的带类型名的值设置⽅法。
通过反射机制可以调⽤私有变量和私有⽅法。但在访问private、protected成员变量和⽅法时必须通过setAccessible(boolean acess)⽅法取消java语⾔检查,否则抛出IllegalAccessException。若JVM的安全管理器设置了相应的安全机制,调⽤该⽅法将抛出SecurityException。
Spring设计了⼀个Resource接⼝,它为应⽤提供了更强的访问底层资源的能⼒。该接⼝拥有对应不同资源类型的实现类。Resource接⼝的主要⽅法:
boolean exists():资源是否存在
boolean isOpen():资源是否打开
URL getURL() throws IOException:若底层资源可以表⽰成URL,该⽅法返回对应的URL对象
File getFile() throws IOException:若底层资源对应⼀个⽂件,该⽅法返回对应的File对象
InputStream getInputStream() throws IOException:返回资源对应的输⼊流
Spring框架使⽤Resource装载各种资源,Resource的具体实现类如下:
ByteArrayResource:⼆进制数组表⽰的资源,⼆进制数组资源可以在内存中通过程序构造
ClassPathResource:类路径下的资源,资源以相对于类路径的⽅式表⽰
FileSystemResource:⽂件系统资源,资源以⽂件系统路径的⽅式表⽰
InputStreamResource:对应⼀个InputStream的资源
ServletContextResource:为访问web容器上下⽂中的资源⽽设计的类,负责以相对于Web应⽤根⽬录的路径加载资源,它⽀持已流和URL 的⽅式访问,在WAR解包的情况下,也可以通过File的⽅式访问,还可以直接从JAR包中访问资源。
UrlResource:封装了java.URL,它使⽤户能够访问任何可以通过URL表⽰的资源。
对资源进⾏编码:
EncodedResource encRes = new EncodedResource(res,"UTF-8");
资源类型的地址前缀
地址前缀⽰例
classpath      classpath:l
对应资源类型:从类路径中加载资源,classpath:和classpath:/是等价的,都是相当于类的跟路径。资源⽂件可以在标准的⽂件系统中,也可以在jar或zip的类包中
file:        file:/l
对应资源类型:使⽤UrlResource从⽂件系统⽬录中装载资源,可采⽤绝对或相对路径
      l
对应资源类型:使⽤UrlResource从Web服务器中装载资源
ftp://        ftp://l
对应资源类型:使⽤UrlResource从FTP服务器中装载资源
没有前缀      l
对应资源类型:根据ApplicationContext具体实现类采⽤对应的类型的Resource
Ant风格资源地址⽀持3种匹配符:
:匹配⽂件名中的⼀个字符
*:匹配⽂件名中任意字符
**:匹配多层路径
Spring定义⼀套资源加载的接⼝,并提供了实现类。ResourceLoader接⼝仅有⼀个getResource(String location)的⽅法,可以根据⼀个资源地址加载⽂件资源。不过这个⽂件资源仅⽀持带资源类型前缀的表达式,不⽀持Ant风格的资源路径表达式。ResourcePatternResolver扩展了ResourceLoader接⼝,定义了⼀个新的接⼝⽅法:getResources(String locationPattern),该⽅法⽀持带资源类型前缀及Ant风格的资源路径的表达式。PathMatchingResourcePatternResolver是Spring提供了标准实现类。
Spring为BeanFactory提供了多种实现,最常⽤的XmlBeanFactory。
BeanFactory最主要的⽅法就是getBean(String beanName),该⽅法从容器中返回特定该名称的Bean。BeanFactory的其他接⼝:ListableBeanFactory:该接⼝定义了访问容器中Bean基本信息的若⼲⽅法
HierarchicalBeanFactory:⽗⼦级联IoC容器的接⼝,⼦容器可以通过接⼝⽅法访问⽗容器。
ConfigurableBeanFactory:增强IoC容器的可定制性,它定义了设置类装载其、属性编辑器、容器初始化后置处理器等⽅法AutowireCapableBeanFactory:定义了将容器中的Bean按某种规则进⾏⾃动装配的⽅法
SingletonBeanRegistry:定义了允许在运⾏期间向容器注册单实例Bean的⽅法
BeanDefinitionRegistry:Spring配置⽂件中每⼀个<bean>节点元素在Spring容器⾥都通过⼀个BeanDefinition对象表⽰,他描述了Bean的配置信息。⽽BeanDefinition Registry接⼝提供了向容器⼿⼯注册BeanDefinition对象的⽅法。
ApplicationContext的主要实现类是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置⽂件,后者默认从⽂件系统中装载配置⽂件。ApplicationContext继承了HierarchicalBeanFactory和ListableBeanFactory接⼝。
ApplicationEventPublisher:让容器拥有发布应⽤上下⽂事件的功能,包括容器启动事件、关闭事件等。实现了ApplicationListener事件监听接⼝的Bean可以接受到容器事件,并对事件进⾏响应处理。在ApplicationContext抽象实现类AbstractApplicationContext中,我们可以发现存在⼀个ApplicationEventMulticaster,它负责保存所有,以便在容器产⽣上下⽂事件时通知这些事件监听者。MessageSource:为应⽤提供il18n国际化消息访问功能。
ResourcePatternResolver:所有ApplicationContext实现类都实现了类似于PathMatchingResourcePatternResolver功能,可以通过带前缀的Ant风格的资源⽂件路径装载Spring的配置⽂件。
LifeCycle:该接⼝提供了start()和stop()两个⽅法,主要⽤于控制异步处理过程。在具体使⽤时,ApplicationContext及具体的Bean都必须同时实现该接⼝,ApplicationContext会将start/stop的信息传递给容器中所有实现了该接⼝的Bean,已达到管理和控制JMX、任务调度等⽬的。
ConfigurableApplicationContext扩展与ApplicationContext,它新增了refresh()和close(),让ApplicationContext具有启动、刷新和关闭应⽤上下⽂的能⼒。在应⽤上下⽂关闭的情况下调⽤refresh()即可启动应⽤上下⽂,在已经启动的状态下,调⽤refresh()则清理缓存并重新装载配置信息,⽽调⽤close()则可关闭应⽤上下⽂。
ApplicationContext和BeanFactory的重⼤区别:BeanFactory在初始化容器时,并未实例化Bean,直到第⼀次访问某个Bean时才实例⽬标Bean;⽽ApplicationContext则在初始化应⽤上下⽂时就实例化所有单实例的Bean。因次,ApplicationContext的初始化事件会⽐BeanFactory稍长,但之后的调⽤没有第⼀次惩罚的问题。
WebApplicationContext是专门为Web应⽤准备的,它允许从相对于Web根⽬录的路径中装载配置⽂件完成初始化⼯作。从WebApplicationContext中可以获得ServletContext的引⽤,整个Web应⽤上下⽂对象将作为属性放置到ServletContext中,以便Web应⽤程序可以访问Srping应⽤上下⽂。Spring专门为次提供⼀个⼯具类WebApplicationContextUtils,通过该类的getWebApplicationContext(ServletContext sc)
⽅法,既可以从ServletContext中获取WebApplicationContext是实例。在WebApplicationContext中还为Bean添加了三个新的作⽤域:request作⽤域、session作⽤域和global session作⽤域。⽽在为Web应⽤环境下,Bean只有singleton和prototype两种作⽤域。
WebApplicationContext定义了⼀个常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下⽂启动
时,WebApplicationContext实例即以此为键放置在ServletContext的属性列表中。
ConfigurableApplicationContext允许通过配置的⽅式实例化WebApplicationContext。
setServletContext(ServletContext servletContext):为Spring设置Web应⽤上下⽂,以便两者整合
setConfigLocations(String[] configLocations):设置Spring配置⽂件地址,⼀般情况下,配置⽂件地址是相对于Web根⽬录的地址。WebApplicationContext的初始化⽅式和BeanFactory、ApplicationContext有所区别。WebApplicationContext秀奥ServletContext实例,也就是说它必须在拥有Web容器的前提下才能完成启动的⼯作。
Spring分别提供了⽤于启动WebApplicationContext的Servlet的Web容器:
org.t.ContextLoaderServlet、org.t.ContextLoaderListener两者的内部都实现了启动WebApplicationContext实例的逻辑,我们只要根据Web容器的具体情况选择两只之⼀,并在l中完成配置就可以了。
由于WebApplicationContext需要使⽤⽇志功能,⽤户可以将Log4J的配置⽂件放置到类路径的WEB-INF/classes下,这时Log4J引擎即可顺利启动。Spring为启动Log4J引擎提供了两个类似于启动WebApplicationContext的实现类:Log4jConfigServlet和Log4jConfigListener。<context-param>
<param-name>contextConfigLocation</param-name>
<paramm-value>
/l,/l
</param-value>
</context-param>
<context-param>
<param-name>log4jConfigLocation</param-name>
<paramm-value>
/WEB-INF/log4j.properties
</param-value>
</context-param>
<servlet>
<servlet-name>log4jConfigServlet</servlet-name>
<servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.t.ContextLoaderServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
通过HierarchicalBeanFactory接⼝,Spring的IoC容器可以建⽴⽗⼦层级关联的容器体系,⼦容器可以访问⽗容器中的Bean,但⽗容器不能访问⼦容器的Bean。在容器内,Bean的id必须是唯⼀的,但⼦容器可以拥有⼀个和⽗容器id相同的bean。⽗⼦容器层级体系增强了Spring 容器架构的扩展性和灵活性。
Bean的⽣命周期:
1.当调⽤者通过getBean(beanName)向容器请求某⼀个Bean时,若容器注册了
org.springframework.beans.factory.InstantiationAwareBeanPostProcessor接⼝,在实例化Bean之前,将调⽤接⼝的postProcessBeforeInstantiation()⽅法。
2.根据配置情况调⽤Bean构造函数或⼯⼚⽅法实例化Bean
3.若容器注册了InstantiationAwareBeanPostProcessor接⼝,在实例化Bean之后,调⽤该接⼝的postProcessAfterInstantiation()⽅法,可在这⾥对已经实例化的对象进⾏相关操作。
4.若Bean配置了属性信息,容器在这⼀步着⼿将配置值设置到Bean对应的属性中,不过在设置每个属性之前先将调⽤InstantiationAwareBeanPostProcessor接⼝的postProcessPropertyValues()⽅法。
5.调⽤Bean的属性设置⽅法设置属性值
6.若Bean实现了org.springframework.beans.factory.BeanNameAware接⼝,将调⽤setBeanName()接⼝⽅法,将配置⽂件中该Bean对应的名称设置到Bean中。
7.若Bean实现了org.springframework.beans.factory.BeanFactoryAware接⼝,将调⽤setBeanFactory()接⼝⽅法,将BeanFactory容器实例设置到Bean中。
8.若BeanFactory装配了org.springframework.fig.BeanPostProcessor后处理器,将调⽤BeanPostProcessor的Object postProcessBeforeInitialization(Object bean,String beanName)接⼝⽅法对Bean进⾏加⼯操作。其中参数bean是当前正在处理的bean,⽽beanName的hi当前Bean的配置名,返回的对象为加⼯处理后的Bean。BeanPostProcessor在Spring框架中占有重要地位,为容器提供对Bean进⾏后加⼯处理的切⼊点。
9.若Bean实现了InitializingBean的接⼝,将调⽤接⼝的afterPropertiesSet()⽅法
10.若在<bean>通过init-method属性定义了初始化⽅法,将执⾏这个⽅法
11.BeanPostProcessor后处理器定义了两个⽅法:其⼀是postProcessBeforeInitializatiopn()在第8步调⽤;其⼆是Object postProcessAfterInitialization(Object bean,String beanName)⽅法,这个⽅法在此时调⽤,容器在此获得对Bean进⾏加⼯处理的机会。12.若在<bean>中指定Bean的作⽤范围为scope='prototype',将Bean返回给调⽤者,调⽤者负责调⽤者后续⽣命的管理,Spring不再管理这个Bean的⽣命周期。若作⽤范围设置为scope='singleton',则将Bean放⼊到Spring IoC容器的缓存池中,并将Bean引⽤返回给调⽤
者,Spring继续对这些Bean进⾏后续的⽣命管理。
13.对于scope='singleton'的Bean,当容器关闭时,将触发Spring对Bean的后续⽣命周期的管理⼯作,⾸先,若Bean实现了DisposableBean接⼝,则将调⽤接⼝的afterPropertiesSet()⽅法,可以在次编写释放资源、记录⽇志等操作。
14.对于scope='singleton'的Bean,若通过<bean>的destroy-method属性指定了Bean的销毁⽅法,Spring将执⾏Bean这个⽅法,完成Bean 资源的释放等操作。
Bean的完整⽣命周期从Spring容器着⼿实例化Bean开始,知道最终销毁Bean,这当中经过了许多关键点,每个关键点都涉及特定的⽅法调⽤,可以将这些⽅法⼤致划分为三类:
Bean⾃⾝的⽅法:若调⽤Bean构造函数实例化Bean,调⽤setter设置Bean的属性值以及通过<bean>的init-method和destroy-method所制定的⽅法;
Bean级⽣命周期接⼝⽅法:如BeanNameAware、BeanFactoryAware、InitializingBean和DisposableBean,这些接⼝⽅法由Bean直接实现
容器级⽣命周期接⼝⽅法:后处理器接⼝⼀般不由Bean本⾝实现,他们独⽴于Bean,实现类以容器附加装置的形式注册到Spring容器中并通过接⼝反射为Spring容器预先识别。Spring容器创建Bean时,这些后处理器都会发⽣作⽤,所以这些后处理器的影响是全局的。
ApplicationContext和BeanFactory的最⼤区别在于前者会利⽤Java的反射机制⾃动识别出配置⽂件中定义的BeanPostProcessor、IntantiationAwareBeanPostProcessor和BeanFactoryProcessor,并将他们注册到应⽤上下⽂中,⽽后者需要在代码中通过⼿⼯调⽤addBeanPostProcessor()⽅法进⾏注册。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。