Bean作用域
首先解释下作用域,java、js都有作用域,它们表示的是变量的可见范围,例如函数中定义的变量只能在这个函数里使用。而Spring容器的作用域是指创建的Bean相对于其他Bean的请求可见范围。
(1)singleton作用域
在每个IOC容器中只创建一个实例,整个生命周期由Spring容器管理。也就是,对于所有获取该bean(singleton)的操作,容器只返回同一个Bean。
单例的实现,我们可以在类上定义静态属性去持有这个实例或者通过注册表的方式去实现。
Spring容器实现是通过注册表的方式,因为第一种是侵入式方式,对于每一个对象,都要实现一个类,很麻烦。
通过实现SingletonBeanRegistry接口,将所要创建的bean放入一个Map对象中,通过beanName来获取对用的bean对象。(大致方法有:是否包含这个bean、获取bean的数量、获取bean的name、获取bean、注册bean)
public interface SingletonBeanRegistry {
void registerSingleton(String var1, Object var2);
Object getSingleton(String var1);
boolean containsSingleton(String var1);
String[] getSingletonNames();
int getSingletonCount();
Object getSingletonMutex();
}
Spring会缓存singleton的bean实例和bean定义,而prototype(往下看)只会缓存bean定义。
(2)prototype
每次向容器获取bean时,都会创建一个新的对象。
GOF原型设计模式:用原型实例指定创建对象的种类,并通过拷贝这些原型创建的对象。
在java里头,原型实例-》class类,原型对象-》实例,可通过clone方法进行拷贝。(侵入式)
而spring中,用bean定义指定创建对象的种类,根据bean定义创建新对象。(非侵入式,可配置)
Web应用中的作用域
(1)request作用域:表示每个请求需要容器创建一个全新Bean。例如表单提交,每次请求新建一个bean来保持这些数据。
(2)session作用域:表示每个会话容器都会创建一个全新Bean。
(3)globalSession:类似session作用域。
自定义Scope
public interface Scope {
//从作用域中获取bean,取不到factory创建新bean
Object get(String var1, ObjectFactory<?> var2);
Object remove(String var1);
//注册销毁毁掉
void registerDestructionCallback(String var1, Runnable var2);
//解析相应上下文数据
Object resolveContextualObject(String var1);
//作用域的会话标识
String getConversationId();
}
通过实现该接口,将具体对象注册到Spring容器
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer”>
<!-- 注入scopes属性 -->
<property name="scopes">
<map>
<entry>
<!-- 指定scope关键字 -->
<key>
<value>thread</value>
</key>
<!-- scope实现 -->
<bean class="spring.chapter3.ThreadScope"/>
</entry>
</map>
</property>
</bean>
然后bean的作用域可以更改啦。
public interface Resource extends InputStreamSource {
//返回java.io.InputStream字节流
InputStream getInputStream() throws IOException;
//当前资源是否存在
boolean exists();
//底层资源是否可读
boolean isReadable();
//true只能被读取一次后关闭以避免资源泄漏,常见resource返回为false
boolean isOpen();
//如果当前Resource代表java.util.URL,则返回URL,否则抛错
URL getURL() throws IOException;
//如果当前Resource代表java.util.URI,则返回URi,否则抛错
URI getURI() throws IOException;
//如果当前Resource代表java.io.File,则返回File,否则抛错
File getFile() throws IOException;
//返回当前Resource代表文件资源的长度
long contentLength() throws IOException;
//底层资源最后修改时间
long lastModified() throws IOException;
//用于创建当前资源的资源, 例如 resource代表文件资源,/user/ ,那么创建的text.txt 在 /user/text.txt
Resource createRelative(String var1) throws IOException;
//获取文件资源的文件路径
String getFilename();
//返回资源的描述符,也就是全路径(实际文件名/实际URL地址)
String getDescription();
}
ResourceLoader接口用于返回Resource对象,可以将其看作一个生产Resource的工厂类。
Spring提供一个适用于所有环境的DefaultResourceLoader实现,可以返回ClassPathResource、UrlResource。ServletContentResourceLoader还提供额外的ServletContentResource。
ResourceLoader加载资源需要使用前缀来指定需要加载的内容:
classpath:path返回ClasspathResource。
http://path和file:path表示返回UrlResource资源,不加前缀,需要根据当前上下文决定。
ClassPathXmlApplicationContext:不指定前缀默认返回ClassPathResource
FileSystemXmlApplicationContext:不指定前缀返回FileSystemResource
WebApplicationContext:不指定前缀默认返回ServletContextResource
public interface ResourceLoaderAware extends Aware {
void setResourceLoader(ResourceLoader var1);
}
ResourceLoaderAware接口,是一个回调标记接口,当有bean实现它时,ApplicationContext会将ResourceLoader(自己)注入到这个bean中。Application已经实现了ResourceLoader。
classpath: 表示支持加载一个Resource。
classpath*:支持加载所有匹配的类路径Resource。
Spring是通过ResourcePatternResolver接口来加载多个Resource的,该接口继承ResourceLoader并添加新的获取一组Resource的方法。
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String var1) throws IOException;
}
ResourceArrayPropertyEditor是用来将路径字符串转为Resource的,PathMatchingResourcePatternResolver解析资源文件的策略接口
FileSystemXmlApplicationContext,在linux不管是否带/,都是相对路径,windows是绝对路径,要想在linux上绝对请使用File:/root/www/……
AOP
横切关注点:一个组件无法完成需要的功能,需要其他组件协助(在组件执行前协助还是执行后协助)
连接点(jointPoint):表示横切关注点的位置在哪(在组件那个地方协助)(Spring只支持方法为连接点)AOP表示在哪里干
切入点(Pointcut):连接点的集合。AOP表示在哪干的集合
通知(Advice):对连接点处进行拓展,前置通知,后置通知,环绕通知。AOP表示增强的功能也就是在连接点干什么
方面/切面(Aspect):通知、引入和切入点的组合。AOP表示在哪干和干什么的集合
引入:为已有的类添加额外新的字段或方法。
目标对象:切入点选择的对象。AOP表示对谁干
AOP代理:通过代理,实现连接点处插入通知。通过代理来增强。AOP中代理可使用CGLIB和JDK动态代理实现。
织入:将切面应用到目标对象,从而创建出AOP代理对象的过程。可以发生在编译器、类装载期、运行期。