关于aop使用java代码实现的流程:
1.准备java测试类PersonAOP(主要在两个run方法指定位置采用aop思想加上指定代码):
import org.springframework.aop.Advisor;
/**
*纯java实现AOP功能范例
*/
public class PersonAOP {
public void run(){
System.out.println("这是第一个run方法");
}
public void run(int i){
System.out.println("这是第二个run"+i+"方法");
}
public void print(){
System.out.println("这是一个打印方法");
}
//是否启用代理模式
public void proxy(Advisor advisor){
}
}
2.为方便扩展,添加指定代码的方法抽象出个父类AOPPoint
import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
/**
* 切入点规则父类
*/
public abstract class AOPPoint {
//切入点
public JdkRegexpMethodPointcut point(String regularExpression) {
JdkRegexpMethodPointcut cut = new JdkRegexpMethodPointcut();
//cut.setPattern("指定明确方法的位置");
cut.setPattern(regularExpression);//或者指定匹配关系的正则表达式
return cut;
}
//通知
//如果在方法提之前需要加入一些操作
public abstract Advice before();
//如果在方法提之后执行
public abstract Advice after();
//如果方法体被包含
public abstract Advice around();
/**
*
* @param regularExpression 可以时匹配的正则表达式,也可以是明确的方法的路径
* @param location
* @return
*/
public abstract Advisor rule(String regularExpression,String location);
}
3.实现类AOPTest
import AOP.AOPPoint;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import java.lang.reflect.Method;
public class AOPTest extends AOPPoint {
@Override
public Advice before() {
Advice before = new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object obj)
throws Throwable {
System.out.println("before...拦截");
}
};
return before;
}
@Override
public Advice after() {
Advice after = new AfterReturningAdvice() {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("afterReturning...拦截");
}
};
return after;
}
@Override
public Advice around() {
Advice advice = new MethodInterceptor() {
//哈哈,看到这个是不是和动态代理中的那个方法很像
@Override
public Object invoke(MethodInvocation methodInv) throws Throwable {
System.out.println("前面拦拦...");
Object resObj = methodInv.proceed();//放行
System.out.println("后面拦拦...");
return resObj;
}
};
return advice;
}
@Override
public Advisor rule(String regularExpression, String location) {
JdkRegexpMethodPointcut cut = super.point(regularExpression);
String judge = location.trim();
Advice advice = null;
switch (judge) {
case "before":
advice = this.before();
break;
case "after":
advice = this.after();
break;
case "around":
advice = this.around();
break;
}
//切面 = 切点 + 通知
Advisor advisor = new DefaultPointcutAdvisor(cut, advice);
return advisor;
}
}
4.组装工厂AOPFactory
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
public class AOPFactory {
/**
* 组装工厂, 说白了就是代理模式的升级版
* @param aa 原型对象,也就是要被切面使用的类
* @param advisor
* @return
*/
public static Object proxy(Object aa, Advisor advisor){
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(aa);//给代理工厂一个原型对象
proxyFactory.addAdvisor(advisor);//给代理工厂一个切面
Object ob = proxyFactory.getProxy();//从代理工厂中获取一个代理后的对象
return ob;
}
}
<!--配置事务管理,如果想更加精细控制,则使用注解事务 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置通知(配置事务执行的方法定义的名称规则) -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP的规则 -->
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut id="pc" expression="execution(* com.zc.service..*Service*.*(..))"/>
<aop:advisor pointcut-ref="pc" advice-ref="myAdvice"/>
</aop:config>
<aop:config proxy-target-class="true"></aop:config>
5测试类JavaAOP
import AOP.impl.AOPTest;
import com.zc.dto.PersonAOP;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.Invocation;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import java.lang.reflect.Method;
/**
* 纯Java的方式实现切面(拦截)技术
*/
public class JavaAOP {
//和动态代理类似
@Test
public void demo(){
//获取切面规则,主要是面向切面的方法,以及切入点的位置(这里有before,after,around三种)
AOPPoint aop = new AOPTest();
Advisor advisor = aop.rule(".*.print.*","before");
//获取代理后的对象
PersonAOP p2 = (PersonAOP) AOPFactory.proxy(new PersonAOP(),advisor);
p2.run();
p2.print();//不会拦
p2.run(3333);
}
}
以上是java代码实现的基本步骤,说白了就是要注意:1切入面(方法),2切入点(移植代码的位置)
了解原理之后在看spring 利用aop完成事务提交和回滚就特别好理解了,直接上代码
xml里面的配置
<!--配置事务管理,如果想更加精细控制,则使用注解事务 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置通知(配置事务执行的方法定义的名称规则) -->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 配置AOP的规则 -->
<aop:config>
<!-- 配置切入点 -->
<!--针对execution(* com.zc.Service..*Service*.*(..))的说明,
* com.zc.service..*Service*.*(..)
* 指的是返回的类型是任意的
com.zc.service 指切面路径
.. 有两种 .表示当前包下面的类 .. 表示当前包及其子包下的所有类
*Service* 类名的规则,中间必须有Service,前后随意
* 表示方法名随意,可指定
(..)参数为任意参
-->
<aop:pointcut id="pc" expression="execution(* com.zc.service..*Service*.*(..))"/>
<aop:advisor pointcut-ref="pc" advice-ref="myAdvice"/>
</aop:config>
<aop:config proxy-target-class="true"></aop:config>
其中给自己挖了个坑,没配aop事务之前在 在用公司给的框架里有这个配置
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor"/>
结果导致一直报异常
org.springframework.beans.factory.NoSuchBeanDefinitionException
后来发现是生成bean和需求产生的bean(加上这个配置后,显示的是个代理bean) 两边不匹配出错,查了下这个
DefaultAdvisorAutoProxyCreator
貌似很强大,待以后研究
参考文章:https://blog.csdn.net/qq_26525215/article/details/52400791