Spring中AOP代理(一个Bean)由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
IOC(反转控制)可以定义为:由IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
Spring中,最基本的IOC容器接口是BeanFactory ,该接口为具体的IOC容器的实现作了最基本的功能规定
DI-Dependency Injection,即依赖注入,组件之间依赖关系由容器在运行期决定。
AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
参见 http://www.cnblogs.com/xrq730/p/4919025.html (非常好)
Spring默认以aspect的定义顺序作为织入顺序,但aspect里面有一个order属性,order属性的数字就是横切关注点的顺序
AOP核心概念
1、横切关注点-------------------------对应一个类(想要把这个类的方法(如日志)加到其他类的方法上的这个类)
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)---------------------对应一个类
类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint)
被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut)------------------定义连接点
对连接点进行拦截的定义
5、通知(advice)-----------------------对应类里的方法
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
<!-- AOP方式事务配置 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 为业务逻辑层的方法解析@DataSource注解 为当前线程的routeholder注入数据源key -->
<bean id="dataSourceAspect" class="com.xxx.util.DataSourceAspect" />
<aop:config proxy-target-class="true">
<aop:aspect id="dataSourceAspect" ref="dataSourceAspect"
order="1">
<aop:pointcut id="tx" expression="execution(* com.xxx..*.*(..)) " />
<aop:before pointcut-ref="tx" method="before" />
</aop:aspect>
</aop:config>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 增删改加入事物控制 -->
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="insert*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="save*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<!-- 查询方法(只读)不用事物控制 -->
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
public class DataSourceAspect
{
/**
* 在dao层方法之前,获取datasource对象之前,在切面中指定当前线程数据源路由的key
*/
public void before(JoinPoint point)
{
Object target = point.getTarget();
System.out.println(target.toString());
String method = point.getSignature().getName();
System.out.println(method);
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();
try
{
Method m = classz[0].getMethod(method, parameterTypes);
System.out.println(m.getName());
if (m != null && m.isAnnotationPresent(DataSource.class))
{
DataSource data = m.getAnnotation(DataSource.class);
System.out.println("用户选择数据库库类型:" + data.value());
HandleDataSource.putDataSource(data.value());
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}