Aop:
横向重复,纵向抽取
Aop基于代理的机制
Spring产生代理对象,
实现的AOp的原理:
动态代理:
被代理对象必须实现接口,如果没有接口将不能使用
对某一个目标中的方法进行增强
cglib代理:
可以对任何类生成代理,他可以目标对象进行继承代理。若目标对象被final修饰则该类不可以生成代理
Spring两者混合使用。
SpringAop开发:
Spring封装了动态代理代码,不需受用书写
可以对任何类进行d代理的增强
Aop术语:
切面(aspect):对象操作过程中的截面,一段程序代码被植入到程序的流程中,(切入点+通知)
连接点(JoinPoint):对象的操作过程中的某个阶段点,目标对象中所有可以增强的方法
切入点(Pointcut):是连接点的集合,目标对象中已经增强的方法
通知(Advice):某个切入点被横切后所取得处理逻辑,增强的代码
目标对象(Target):所有被通知的对象
织入(Weaving):将切面功能应用到目标对象的过程。织入时期:(编译时期,类加载时期,执行期,
引入:已编译的类在运行期动态加载属性和方法。
Spring切入点:他表示注入切面的位置有以下三种切入点:静态切入点,动态切入点,其他切入点
静态切入点:
静态往往意味着不变,只能应用在相对不变的位置上 静态切入点在某个方法名上是织入切面,在织入代码前,进象进行方法的匹配,判断当前的正在调用的方法是不是已经定义了静态切入点定义过说明匹配成功,织入切面,如没有定义为静态的切入点这匹配失败,不进行织入切面。Pointcut接口是切入点的定义接口,用它来规定可切入的链接点的属性,通过对该接口的来扩展处理其他类型的链接点
public interface Pointcut{
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
使用ClassFilter接口匹配目标类
public interface ClassFilter{
//与目标类相匹配
boolean matches(Class class);
}
动态切入点:
可以应用在相对变化的位置上,
Aspect:
就是Spring的切面,他是对象操作过程的截面, 是对系统中的对象操作过程中的截面的逻辑进行模块化的封装的Aop概念实体
Aop事务:
Spring 事务应用的方法上的策略的描述,传播行为,隔离级别,只读,超时属性,
编程式事务管理:
在Spring中主要使用PlatformTransactionManager接口的事务管理器或者是TransactionTemplate,后者符合模板形式
声明式事务管理:
在声明的事务中不涉及组建依赖关系,通过AOP来实现事务管理,无需编写任何代码就可以实现基于容器的事务管理,推荐使用 常用TransactionProxyFactoryBean完成声明式事务管理,设置代理的目标对象,代理对象生成的方法和事务的生成方式和事务属性,代理对象是在 目标对象上生成的包含事务和AOP切面的新的对象,可以付给目标的引用代替目标对象,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
<!-- 指定spring读取db.properties配置 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 事务模板对象 -->
<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
<property name="transactionManager" ref="transactionManager" ></property>
</bean>
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<!-- 以方法为单位,指定方法应用什么事务属性
isolation:隔离级别
propagation:传播行为
read-only:是否只读
-->
<tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
<tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- 配置织入 -->
<aop:config >
<!-- 配置切点表达式 *号代表的任意的参数, -->
<aop:pointcut expression="execution(* service.*ServiceImpl.*(..))" id="txPc"/>
<!-- 配置切面 : 通知+切点
advice-ref:通知的名称
pointcut-ref:切点的名称
-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config>
<!-- 1.将连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
<property name="driverClass" value="${jdbc.driverClass}" ></property>
<property name="user" value="${jdbc.user}" ></property>
<property name="password" value="${jdbc.password}" ></property>
</bean>
<!-- 2.Dao-->
<bean name="accountDao" class="dao.AccountDaoImpl" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 3.Service-->
<bean name="accountService" class="service.AccountServiceImpl" >
<property name="ad" ref="accountDao" ></property>
<property name="tt" ref="transactionTemplate" ></property>
</bean>
</beans>
在spring中的Aop模块中还用一些比如通知:
通知:就是某个切点被横切以后所采取的的处理逻辑,某个切入点被横切后所取得处理逻辑,增强的代码
/**
* 通知类
* @author leoi555
*
*/
public class Advice {
//前置通知:目标方法之前调用
//后置通知:exception时,不会调用执行后调用
//环绕通知:在目标方法前后都调用
//异常拦截通知:出现异常就会调用
//后置通知,无论是否异常都要调用
//前置通知
public void before() {
System.out.println("前置通知");
}
//后置通知
public void afterReturning() {
System.out.println("后置通知异常不会调用");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
Object proceed = pjp.proceed();//调用目标方法
System.out.println("这是环绕通知之后的部分!!");
return proceed;
}
//异常通知
public void afterException() {
System.out.println("异常通知");
}
//后置通知
public void after() {
System.out.println("后置通知出现异常也会调用");
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<!--准备工作:导入aop约束的命名空间 -->
<!-- 1.配置目标对象 -->
<bean name="userService" class="com.leo.service.impl.UserServiceImpl"></bean>
<!-- 2.配置通知对象 -->
<bean name="Advice" class="com.leo.aop.Advice"></bean>
<!-- 3.配置通知织入目标对象 -->
<aop:config>
<!-- 配置切入点
public void com.leo.service.UserServiceImpl.save()
void com.leo.service.UserServiceImpl.save()
*com.leo.service.UserServiceImpl.save()
*com.leo.service.UserServiceImpl.*()
*com.leo.service.*ServiceImpl.*(..)//任意的参数,后缀为ServiceImpl的类下任意的方法
*com.leo.service..*ServiceImpl.*(..)
-->
<aop:pointcut expression="execution(pubic void com.leo.service.UserServiceImpl.save())" id="pc"></aop:pointcut>
<aop:aspect ref=" Advice">
<!-- 指定为beafore方法作为前置通知 -->
<aop:before method="before" pointcut-ref="pc"></aop:before>
<!--后置 -->
<aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
<!-- 环绕 -->
<aop:around method="around" pointcut-ref="pc"></aop:around>
<!-- 后置异常 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"></aop:after-throwing>
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="pc"></aop:after>
</aop:aspect>
</aop:config>
</beans>
测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/leo/aop/applicationContext.xml")
public class Demo {
@Resource(name="userService")
private UserService us;
@Test
public void fun1(){
us.save();
}
}
动态代理:
//=>动态代理
public class UserServiceProxyFactory implements InvocationHandler {
public UserServiceProxyFactory(UserService us) {
super();
this.us = us;
}
private UserService us;
public UserService getUserServiceProxy(){
//生成动态代理
UserService usProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
UserServiceImpl.class.getInterfaces(),
this);
//返回
return usProxy;
}
@Override
public Object invoke(Object arg0, Method method, Object[] arg2) throws Throwable {
System.out.println("打开事务!");
Object invoke = method.invoke(us, arg2);
System.out.println("提交事务!");
return invoke;
}
}
cglib代理:可以生成字节码
//=>cglib代理
public class UserServiceProxyFactory2 implements MethodInterceptor {
public UserService getUserServiceProxy(){
Enhancer en = new Enhancer();//帮我们生成代理对象
en.setSuperclass(UserServiceImpl.class);//设置对谁进行代理
en.setCallback(this);//代理要做什么
UserService us = (UserService) en.create();//创建代理对象
return us;
}
@Override
public Object intercept(Object prxoyobj, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
//打开事务
System.out.println("打开事务!");
//调用原有方法
Object returnValue = methodProxy.invokeSuper(prxoyobj, arg);
//提交事务
System.out.println("提交事务!");
return returnValue;
}
}
测试:
public class Demo {
@Test
//动态代理
public void fun1(){
UserService us = new UserServiceImpl();
UserServiceProxyFactory factory = new UserServiceProxyFactory(us);
UserService usProxy = factory.getUserServiceProxy();
usProxy.save();
//代理对象与被代理对象实现了相同的接口
//代理对象 与 被代理对象没有继承关系
System.out.println(usProxy instanceof UserServiceImpl );//false
}
@Test
public void fun2(){
UserServiceProxyFactory2 factory = new UserServiceProxyFactory2();
UserService usProxy = factory.getUserServiceProxy();
usProxy.save();
//判断代理对象是否属于被代理对象类型
//代理对象继承了被代理对象=>true
System.out.println(usProxy instanceof UserServiceImpl );//true
}
}
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB
AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:
1、定义普通业务组件。2、定义切入点,一个切入点可能横切多个业务组件。3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作
所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法。