1、明确Spring是个什么东西后,做个简单的例子,如:
https://blog.csdn.net/soonfly/article/details/68498742
2、容器管理的对象是单例模式的吗?
是的
3、容器管理的对象是线程安全的吗?如果不是的话怎么整?
不是线程安全的
解决办法:
1.在Bean对象中尽量避免定义可变的成员变量;
2.在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中
4、容器获取上下文的方法有几种?分别是什么?
大致3种,
• XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;
(1) File file = new File("fileSystemConfig.xml");
Resource resource = new FileSystemResource(file);
BeanFactory beanFactory = new XmlBeanFactory(resource);
(2)
Resource resource = new ClassPathResource("classpath.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
• ClassPathXmlApplicationContext:ApplicationContext实现,从classpath获取配置文件;
BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath.xml");
• FileSystemXmlApplicationContext:ApplicationContext实现,从文件系统获取配置文件。
BeanFactory beanFactory = new FileSystemXmlApplicationContext("fileSystemConfig.xml");
ApplicationContext完全继承BeanFactory,因而BeanFactory所具有的语义也适用于ApplicationContext。
5、DispachterServlet是啥玩意?这东西如何配置
DispatcherServlet提供Spring Web MVC的集中访问点,而且负责职责的分派。
5.1、DispatcherServlet在web.xml中的配置
<servlet>
<servlet-name>chapter2</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>chapter2</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
该DispatcherServlet默认使用WebApplicationContext作为上下文,Spring默认配置文件为“/WEB-INF/[servlet名字]-servlet.xml”。
5.2、在/WEB-INF/[servlet名字]-servlet.xml中配置每个请求用那个类处理的具体规则。
6、为啥Spring Bean设计的可以配置那么多别名干嘛?设计意图是什么?
暂时还没有找到答案
7、 Spring注入的两种方法:构造器注入和 setter注入,那种方法更好?
setter注入的优势:
1. 对于习惯了传统JavaBean开发的程序员而言,通过setter方法设定依赖关系显得更加直
观,更加自然。
2. 如果依赖关系(或继承关系)较为复杂,那么构造器注入会使构造函数也会相当庞大(我们需
要在构造函数中设定所有依赖关系),此时setter注入往往更为简洁。
3. 对于某些第三方类库而言,可能要求我们的组件必须提供一个默认的构造函数(如Struts
中的Action),此时构造器注入的依赖注入机制就体现出其局限性。
构造器注入的优势:
1. “在构造期即创建一个完整、合法的对象”,对于这条Java设计原则,构造器注入无疑是最好的
响应者。
2. 避免了繁琐的setter方法的编写,所有依赖关系均在构造函数中设定,依赖关系集中呈现,
更加易读。
3. 由于没有setter方法,依赖关系在构造时由容器一次性设定,因此组件在被创建之后即处于
相对“不变”的稳定状态,无需担心上层代码在调用过程中执行setter方法对组件依赖关系
产生破坏,特别是对于Singleton模式的组件而言,这可能对整个系统产生重大的影响。
4. 同样,由于关联关系仅在构造函数中表达,只有组件创建者需要关心组件内部的依赖关系。
对调用者而言,组件中的依赖关系处于黑盒之中。对上层屏蔽不必要的信息,也为系统的
层次清晰性提供了保证。
5. 通过构造器注入,意味着我们可以在构造函数中决定依赖关系的注入顺序,对于一个大量
依赖外部服务的组件而言,依赖关系的获得顺序可能非常重要,比如某个依赖关系注入的
先决条件是组件的DataSource及相关资源已经被设定。
8、Spring内部Bean定义有什么用?
作用类型于内部类,可以隐藏实现细节。
<bean id="textEditor" class="com.jsoft.testspring.testinnerbean.TextEditor">
<property name="SpellChecker">
<!--相当于把一个实例注入到另一个实例中-->
<bean id="spellCheckerId" class="com.jsoft.testspring.testinnerbean.SpellChecker"></bean>
</property>
</bean>
外围:
public class TextEditor {
private SpellChecker spellChecker;
public void setSpellChecker(SpellChecker spellChecker){
System.out.println("TextEditor通过setter初始化");
//初始化内部
this.spellChecker = spellChecker;
}
public void spellCheck() {
//调用内部的实现
this.spellChecker.checkSpelling();
}
}
内部:
public class SpellChecker {
public SpellChecker(){
System.out.println("SpellChecker无参数构造函数初始化");
}
public void checkSpelling(){
System.out.println("SpellChecker检查方法");
}
}
9、Spring Bean出现循环依赖咋整?
这个事分三种情况:
1、通过构造器注入时:这种情况没招了,只能抛出异常BeanCurrentlyInCreationException来告诉你循环依赖了
2、完全通过setter注入时:这种情况也没招了,因为因为“prototype”作用域的Bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
3、通过构造器注入但未完成其他步骤(如setter注入)的Bean:这种情况下有个招,就是提前暴露这种 通过构造器注入但未完成其他步骤(如setter注入)的Bean。
//提前暴露的方法
addSingletonFactory(beanName, new ObjectFactory() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
10、Spring Bean的作用域是什么意思?有什么区别?
一般Spring Bean的作用域分为两种:singleton和prototype.
区别:
- singleton
单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例;注意这里的Spring singleton模式是默认缺省的饿汉模式,启容器时(即实例化容器时),为所有spring配置文件中定义的bean都生成一个实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为。
- prototype
原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例。 这东西是new出来的,较浪费性能。
11、Spring的方法注入使用了cglib,cglib到底是一个啥东西?
CGLIB就是一个代码包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。
CGLIB原理
动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
CGLIB底层
使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
CGLIB缺点
对于final方法,无法进行代理
12、加载资源的时候,“classpath:”这些前缀都是干嘛的?为啥要整这些前缀?
在使用Spring之前,当我们处理一些外部资源(URL资源、File资源资源、ClassPath相关资源)的时候需要写大量的样板代码,什么打开资源、读取资源、关闭资源等等,代码显得很臃肿。
这时Spring闪亮登场,它提供一个Resource接口来统一这些底层资源一致的访问,我们再也不用写一些没用的样板代码了,但是在加载资源的时候Spring怎么知道你要加载什么资源呢?就是通过这些前缀,(classpath:path、http://path、file:path),这样不同的资源就区分开了。
“classpath:path”表示返回ClasspathResource
“http://path”和“file:path”表示返回UrlResource资源
不加前缀则需要根据当前上下文来决定
13、如何理解Spring中使用SpEL表达式?不用这东西行不行?
这就是相当于你为什么要在程序中使用Java的三目运算,因为它可以简化代码,不然你就需要写一个if-else判断。
可以用最简短的语句表达出最多的意思。
就我个人理解:这个SpEL表达式就相当于面向过程的一门语言,在Java的面向对象的语言中插入使用面向过程的语言,使程序的表达性更强。
14、SpEL表达式具体用法?
http://jinnianshilongnian.iteye.com/blog/1418309
15、AOP中<aop:advisor>
这个节点是干嘛用的?与<aop:aspect>
有什么区别?
没区别
< aop:aspect>:定义切面(切面包括通知和切点)
< aop:advisor>:定义通知器(通知器跟切面一样,也包括通知和切点)
< aop:advisor>多用于事务,其他情况不推荐使用,因为它需要实现接口,属于侵入式编程。
16、基于Schema的AOP和基于@AspectJ的AOP有什么区别?
基于Schema的AOP就是基于xml
基于@AspectJ的AOP就是基于注解
17、AspectJ类型匹配的通配符?
*
:匹配任何数量字符;
..
:(两个点)匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+
:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
18、基于注解的AOP如何实现?
首先切面包括切点和通知
/**
* 切面
* @author Bird
*
*/
@Aspect
public class MyInterceptor {
@Pointcut("execution(* com.bird.service.impl.PersonServiceBean.*(..))")
private void anyMethod(){}//定义一个切点
@Before("anyMethod() && args(name)")
public void doAccessCheck(String name){//定义通知
System.out.println(name);
System.out.println("前置通知");
}
在bean.xml中
<aop:aspectj-autoproxy/>
<bean id="业务id" class="业务类"/>
<bean id="切面id" class="切面类"/>
19、通知方法是否可以获取被通知方法的参数值?如何获取?
可以。
使用JoinPoint获取:
Spring AOP提供使用org.aspectj.lang.JoinPoint类型获取连接点数据,任何通知方法的第一个参数都可以是JoinPoint(环绕通知是ProceedingJoinPoint,JoinPoint子类),当然第一个参数位置也可以是JoinPoint.StaticPart类型,这个只返回连接点的静态部分。
20、【构造器注入】中的参数名注入限制”在class文件中没生成变量调试信息是获取不到方法参数名字的”,这种情况如何获取被通知方法的参数值?
通过“argNames”属性指定了参数名,通过实验可得:
接下一篇博客:Spring学习问题100问(5/2)