自制aop和注解

本文讲述了在项目中遇到的Spring MVC与Spring AOP整合时的问题,主要涉及多数据源切换和切面配置。由于Spring MVC和Spring扫描相同包导致DAO层被错误扫描,使得AOP切面无法生效。解决方案是将AOP配置放入spring-mvc.xml中,并确保Spring MVC不扫描@Service注解的类,以避免事务配置失效。
摘要由CSDN通过智能技术生成

项目使用了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 中的事务配置不起作用,发生异常时,无法对数据进行回滚。以上就是原因所在.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值