我爱编程

Spring学习

2017-05-22  本文已影响0人  newcih

[TOC]

CGLIB与JDK动态代理

使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点可以从Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)中看得很清楚;第二个传入参数interfaces就是需要代理实例实现的接口列表。对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK动态代理技术显然已经黔驴技穷,CGLIB作为一个替代者,填补了这些空缺。

proxy-target-class

proxy-target-class这个属性是决定基于接口还是基于类的代理被创建,默认为false。如果proxy-target-class属性值被设置为true,那么基于类的代理将起作用(这个时候需要cglib库)。如果proxy-target-class被设置为false或者这个属性被省略,那么表示使用JDK动态代理织入增强,但是,即使设置为false,如果目标类没有声明接口,则Spring将自动使用CGLIB动态代理。

通俗理解:当要使用实现了某个接口的类让Spring来生成Bean时,无需再AOP配置中添加proxy-target-class,因为它默认是false。但如果要使用一个指定的类,让Spring来生成Bean,并使用它的某个方法时,需要在AOP配置上加上一句proxy-target-class=true,否则使用CGLIB,会出现

Java.lang.ClassCastException:com.sun.proxy.$Proxy6 cannot be cast to glut.daoImpl.DAOImpl

类似的错误。

使用@Autowired和@Resource自动装配Bean

解决方案

从Spring2.5起,可以通过@Autowired或者@Resource注解一个设值方法,构造程序,字段甚至任意方法自动装配特定的属性。

工作原理

为了要求Spring自动装配具有@Autowired或者@Resource注解的属性,你必须在IoC容器中注册一个AutowiredAnnotationBeanPostProcess实例。如果你使用一个Bean工厂,就必须通过API注册这个Bean后处理器,否则,你只能在你的应用上下文里声明一个实例。

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

你也可以简单地在Bean配置文件中包含<context:annotation-config>元素,这将自动注册一个AutowiredAnnotationBeanProcessor实例。

<context:annotation-config/>
@Autowired
@Qualifier("datePrefixGenerator")
@Resouce(name = "datePrefixGenerator")

从Classpath中扫描组件

有了应用到组件类的典型化注解,就能通过声明一个XML元素<context:component-scan>,要求Spring扫描这些注解。在这个元素中,你必须指定扫描组件所用的包。然后指定的包和子包都将被扫描。Spring将把类名第一个字符小写,对其余部分采用Camel-cased命名法组成Bean名称。

Camel-cased命名法:当一个命名包含多个单词时,每个单词的第一个字母大写

因此,下面的语句是有效的(假定你已经实例化了一个包含<context:component-scan>元素的应用上下文)

SequenceService service = (SequenceService)context.getBean("sequenceService");

注意,这个元素还将注册一个AutowiredAnnotationBeanPostProcessor实例,这个实例能够自动装配带有@Autowired注解的属性。

过滤扫描的组件

默认情况下,Spring将检测所有用@Component,@Repository,@Service,@Controller或者本身加上@Component注解的自定义注解类型。你可以应用一个或多个包含/排除过滤器自定义这一扫描。Spring支持4中过滤器表达式。annotation和assignable类型用于指定过滤的注解类型和类/接口。regex和aspectj类型允许指定正则表达式和AspectJ切入点表达式匹配类。你还可以用use-default-filters属性禁用默认过滤器。
例如,下面的组件扫描包含了所有名称中包含Dao或Service的类,排除带有@Controller注解的类:

<beans ...>
    <context:component-scan base-package="com.apress.sequence">
        <context:include-filter type="regex"
            expression="com\.apress\.sequence\..*Dao.*"/>
    </context:component-scan>
</beans>

因为你已经应用了include过滤器检测所有名称包含Dao或者Service的类,SequenceDaoImpl和SequenceService组件就能在没有典型化注解的情况下被自动检测出来。

命名检测到的组件

默认情况下,Spring将非限定类名的第一个字符改为小写来命名检测到的组件。你可以在典型化注解值中显式地指定组件的名称。

设置Bean作用域

在Spring 2.x或者更新版本中,Bean的作用域在<bean>元素的scope属性中设置。默认情况下,Spring为IoC容器中声明的每个Bean创建一个实例,这个实例将在整个IoC容器的范围内共享。所有后续的getBean()调用和Bean引用都将返回这个独特的Bean实例。这个作用于称为singleton,是所有Bean的默认作用域。

作用域 描述
Singleton 每个Spring IoC容器创建一个Bean实例
Prototype 每次请求时创建一个新的Bean实例
Request 为每个HTTP请求创建一个Bean实例,仅在Web应用上下文中有效
Session 为每个HTTP会话创建一个Bean实例,仅在Web应用上下文中有效
GlobalSession 为每个全局HTTP会话创建一个Bean实例,仅在门户应用上下文有效

自定义Bean初始化和析构

下面的列表展示了Spring IoC容器管理Bean周期的步骤。这个列表将随着IoC容器更多特性的引入而扩展。

  1. 构造程序或者工厂方法创建Bean实例

Spring有三种识别初始化和析构回调方法的方式。

  1. 你的Bean可以实现 InitializingBeanDisposableBean 生命周期接口,并且实现用于初始化和析构的 afterPropertiesSet()destory() 方法
public class Cashier implements InitializingBean, DisposableBean {
    ...
    public void afterPropertiesSet() throws Exception {
        openFile();
    }
    public void destory() throws Exception {
        closeFile();
    }
}

但是,实现这些专利接口将会使你的Bean变成Spring专用的,无法再Spring IoC容器之外重用

<bean id="cashier1" class="..." init-method="openFile" destory-method="closeFile"/>
public class Cashier {
    ...
    @PostConstruct
    public void openFile() throws IOException {...}
    
    @PreDestory
    public void closeFile() throws IOException {...}
}

启用Spring的AspectJ注解支持

在Bean配置文件中定义一个空的XML元素<aop:aspectj-autoproxy>,就可以启用Spring IoC容器中的AspectJ注解支持。然后,Spring将自动为匹配你的AspectJ aspect的所有Bean创建代理。对于接口不可用或者没有用于应用设计中的情况,可以依靠CGLIB创建代理。为了启用CGLIB,必须在<aop:aspectj-autoproxy>中设置proxy-target-class=true属性。

用AspectJ注解声明aspect

  1. 前置通知(Before advice
    为了创建在程序特定执行点之前处理横切关注点的前置通知,你可以使用@Before注解,并将切入点表达式作为注解值
@Aspect
public class CalculatorLoggingAspect {
    @Around("execution(* *.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
    ....
    }
}
上一篇 下一篇

猜你喜欢

热点阅读