自制aop和注解
来源:互联网 发布:广州万维软件 编辑:程序博客网 时间:2024/05/01 17:48
项目使用了jdbc的多数据源连接,这我要吐槽一下原来的项目了。没接口,代码写在jsp中。我也是服了,spring扫描包和springmvc扫描一样的包,这就是带我今天入坑的原因之一。
//创建叫做DataSource的注解,可以作用在类上和方法上@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value(); }
一个简单的注解,主要是为了切换线程对象中的数据源,让多数据源可以切换使用。
<bean id="dataSourceAspect" class="com.ht.Aspect.DataSourceAspect" ></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="dataSourceAspect"> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.ht.dao.*.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept"/> <aop:after pointcut-ref="dataSourcePointcut" method="intercept"/> </aop:aspect> </aop:config>
public class DataSourceAspect { /** * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception */ public void intercept(JoinPoint point) throws Exception { //得到拦截类 Class<?> target = point.getTarget().getClass(); //得到实际拦截的方法 //即这个类哪个方法执行了 MethodSignature signature = (MethodSignature) point.getSignature(); // 默认使用目标类型的注解,如果没有则使用其实现接口的注解 for (Class<?> clazz : target.getInterfaces()) { //迭代出类的接口,实例一般是实例出这个接口的实例对象 //先看看接口中有没有配置注解,配置了就执行。 resolveDataSource(clazz, signature.getMethod()); } //最后查看实现的类,但是类中配置了注解的不同值,会覆盖接口的。 resolveDataSource(target, signature.getMethod()); } /** * 提取目标对象方法注解和类型注解中的数据源标识 * * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); DataSourceContextHolder.setDataSourceType(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); DataSourceContextHolder.setDataSourceType(source.value()); } } catch (Exception e) { System.out.println(clazz + ":" + e.getMessage()); } }}
这是我配置的切面。然后我发现我的切面配置启动不报错,但是没有效果,我检查完配置路径发现没有问题,然后寻找问题,在博客中得到了答案。
当你需要对collection层进行切面编程时:(部分借鉴)CGLIB代理配置在了applicationContext.xml 核心配置文件中,该配置文件会被ContextLoaderListenerclass加载,Spring会创建一个WebApplicationContext上下文,称为父上下文(父容器) ,保存在ServletContext中,key为WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。
而spring-mvc.xml是DispatcherServlet,可以同时配置多个,每个 DispatcherServlet有一个自己的上下文对象(WebApplicationContext),称为子上下文(子容器),子上下文可以访问父上下文中的内容,但父上下文不能访问子上下文中的内容。 它也保存在 ServletContext中,key是”org.springframework.web.servlet.FrameworkServlet.CONTEXT”+Servlet名称
当spring加在父容器的时候就会去找切入点,但是这个时候切入的controller是在子容器中的,父容器是无法访问子容器,所以就拦截不到。如果将上述的配置文件放到spring-mvc.xml中,那么问题就解决了。我已经测试可以通过URL访问触发切点了。
解决办法就是把aop放入springmvc中。
但是问题又来了,我明明是对dao层做切面为什么不行呢?查看了配置我知道了,这原来的扫描包是spring扫描全部包,springmvc也扫描全部包。然后就冲突了,dao层被springmvc扫描了。下面的要注意。
Spring MVC 和 Spring 整合的时候,SpringMVC的spring-mvc.xml文件中配置扫描包,不要包含 service的注解,Spring的applicationContext.xml文件中配置扫描包时,不要包含controller的注解。
Spring MVC启动时的配置文件,包含组件扫描、url映射以及设置freemarker参数,让spring不扫描带有@Service注解的类。为什么要这样设置?
因为spring-mvc.xml与applicationContext.xml不是同时加载,如果不进行这样的设置,那么,spring就会将所有带@Service注解的类都扫描到容器中,等到加载applicationContext.xml的时候,会因为容器已经存在Service类,使得cglib将不对Service进行代理,直接导致的结果就是在applicationContext 中的事务配置不起作用,发生异常时,无法对数据进行回滚。以上就是原因所在.
- 自制aop和注解
- 【Day02】Aop注解和Aspectj注解+JdbcTemplate
- 传智播客 Spring学习 ,注解和AOP
- 采用spring AOP 和注解解决日志
- 注解和声明方式实现AOP
- 使用 AOP 和注解实现方法缓存
- spring中IOC和AOP详情注解
- Spring4--2.bean注解和AOP
- 【spring】AOP xml和注解实现方式
- Spring-AOP和事务实践(注解方式
- aop注解
- aop注解
- spring注解配置bean和注解配置aop
- spring(AOP) 注解实现aop
- 基于Spring aop 和JAVA注解方式添加日志
- 基于AOP和注解简化异步化处理
- 基于Spring aop 和JAVA注解方式添加日志
- 利用Spring AOP自定义注解解决日志和签名校验
- JAVA Script的奇怪bug
- tensorflow学习
- 第一次写csdn博客
- 互联网协议入门
- Java基础:深入剖析Java中的装箱和拆箱
- 自制aop和注解
- 冈萨雷斯数字图像处理学习6:形态学
- 手机中删除的照片如何恢复的五大解决方法
- 关于C中指针的引用,解引用与脱去解引用
- 初识卷积神经网络(CNN)
- 轰炸
- 华为HCNA学习笔记----第一天
- android 获取android手机ip地址
- SQL必知必会