Spring学习问题100问(5/1)

1、明确Spring是个什么东西后,做个简单的例子,如:

https://blog.csdn.net/soonfly/article/details/68498742

2、容器管理的对象是单例模式的吗?

是的

3、容器管理的对象是线程安全的吗?如果不是的话怎么整?

不是线程安全的

解决办法:
1.在Bean对象中尽量避免定义可变的成员变量;
2.在bean对象中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中

4、容器获取上下文的方法有几种?分别是什么?

大致3种,

• XmlBeanFactory:BeanFactory实现,提供基本的IoC容器功能,可以从classpath或文件系统等获取资源;

1File 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)

猜你喜欢

转载自blog.csdn.net/gogletech/article/details/80323517