首页 新闻 会员 周边

Spring AOP 如何得到通过被代代理后的真实对象

0
悬赏园豆:100 [已解决问题] 解决于 2017-10-16 14:49

  1)首先是接口和实现类:

package com.yidu.domain;

/**
 * 类的描述:接口
 * @date 2017年8月29日
 */
public interface ClassService {
    /**
     * 保存
     */
    public void save();
}

package com.yidu.aop;

import com.yidu.domain.ClassService;

/**
 * 类的描述:实现类
 * @date 2017年8月29日
 */
public class ClassServiceImpl implements ClassService{
    public int i=0;

    /**
     * @return
     */
    public int getI() {
        return i;
    }

    /**
     * @param i
     */
    public void setI(int i) {
        this.i = i;
    }

    /**
     * 保存
     */
    public void save(){
        System.out.println("================="+i);
    }
}

  2)然后是切入类:

package com.yidu.aspect;


import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 类的描述:切入类
 * @date 2017年8月29日
 */
public class ClassAspect {
    
    /**
     * 环绕通知
     * @param pjp
     * @return
     * @throws Throwable
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("注入:环绕通知--开始!");
        Object impl=pjp.getTarget();
        Method m = impl.getClass().getMethod("setI", int.class);//得到方法setI
        m.invoke(impl, 1);//开始之前,设置i=1
        Object o = pjp.proceed();//执行需要增强方法
        m.invoke(impl,0);//结束之后,设置i=0
        System.out.println("注入:环绕通知--结束!");
        return o ;
    }

}

 

  3)接着是上下文环境配置文件:

  <?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
    
    <!-- 主体业务:目标类 -->
    <bean id="classService" class="com.yidu.aop.ClassServiceImpl"/>
    <!-- 切面:通知类 -->
    <bean id="classAspect" class="com.yidu.aspect.ClassAspect"/>
    
    <!-- aop编程 -->
    <aop:config>
        <aop:aspect ref="classAspect">
            <aop:pointcut expression="execution(* com.yidu.aop.ClassServiceImpl.save(..))" id="business"/>
            <aop:around method="doAround" pointcut-ref="business"/>
        </aop:aspect>
    </aop:config>
</beans>

  4)最后是测试类:

package com.yidu.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 类的描述:测试类
 * @date 2017年8月29日
 */
public class ClassTest {

    /**
     * 主方法
     * @param args
     */
    public static void main(String[] args){
        //得到上下文环境
        ApplicationContext application=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //得到内容容器
        Object obj=application.getBean("classService");//这里得到的bean是不确定的、可更换的,所以不能转换成具体的接口
        
        /*
             1.该bean有一个没有参数的save方法
             2.该bean有一个int型变量i,以及相应的setget方法
             3.要求执行save方法
             4.最后取出i,然后输出
        */
        
        
        
    }
    
}

  请教各位大神,如何在这个测试类中,获得被代理的真实对象?

小兵乙的主页 小兵乙 | 初学一级 | 园豆:112
提问于:2017-08-30 20:39
< >
分享
最佳答案
1

我对AOP也理解得不深

我觉得是可以转换的,就好像你在spring框架中配置了AOP,但是实际调用的时候,还是用的原来的类, 只是在执行的时候,框架发现你调用的方法配置了AOP,所以生成代理类来执行你的逻辑,

收获园豆:100
苍枫露雨 | 小虾三级 |园豆:1027 | 2017-09-01 16:32

测试很多遍了,还是转换不了。

这位兄弟,代码就这点,逻辑也简单,你可以复制下来,测试一下!

小兵乙 | 园豆:112 (初学一级) | 2017-09-03 18:25

@小兵乙: 

你使用这个方法试一试:

<T> T getBean(String name, Class<T> requiredType) throws BeansException;
苍枫露雨 | 园豆:1027 (小虾三级) | 2017-09-04 10:29

@苍枫露雨: 只有一个接口,猜测着试了一下,

package com.yidu.domain;


/**
 * 类的描述:接口
 * @date 2017年8月29日
 */
public interface ClassService {
    /**
     * 保存
     */
    public void save();
    
    public <T> T getBean();

    public <T> T getBean(String name, Class<T> requiredType);
}

package com.yidu.aop;

import com.yidu.domain.ClassService;

/**
 * 类的描述:实现类
 * @date 2017年8月29日
 */
public class ClassServiceImpl implements ClassService{
    public int i=0;

    /**
     * @return
     */
    public int getI() {
        return i;
    }

    /**
     * @param i
     */
    public void setI(int i) {
        this.i = i;
    }

    /**
     * 保存
     */
    public void save(){
        System.out.println("================="+i);
    }
    
    
    @Override
    public ClassServiceImpl getBean() {
        return this;//返回自己(实现类本身)
    }
    
    @Override
    public <T> T getBean(String name, Class<T> requiredType) {
        return (T) this;
    }
}

package com.yidu.test;


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yidu.aop.ClassServiceImpl;
import com.yidu.domain.ClassService;
import com.yidu.domain.Computer;

/**
 * 类的描述:测试类
 * @date 2017年8月29日
 */
public class ClassTest {

    /**
     * 主方法
     * @param args
     */
    @SuppressWarnings("resource")
    public static void main(String[] args){
        //得到上下文环境
        ApplicationContext application=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //得到内容容器
        ClassService cls=(ClassService) application.getBean("classService");//这里得到的bean是不确定的、可更换的,所以不能转换成具体的接口
        cls.save();
        ClassServiceImpl impl=cls.getBean();//调用返回this的方法
        System.out.println("i="+ impl.getI());//取i的值
    }
    
}

可还是不行

注入:前置通知!
=================10
注入:后置通知!
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy3 cannot be cast to com.yidu.aop.ClassServiceImpl
    at com.yidu.test.ClassTest.main(ClassTest.java:35)


恕我愚钝,你这个抽象方法,到底是怎么用的?

<T> T getBean(String name, Class<T> requiredType) throws BeansException;

小兵乙 | 园豆:112 (初学一级) | 2017-09-05 21:54

@小兵乙: 

你看下ApplicationContext 的源码,我也是看ApplicationContext找的,试一试,

ClassService cls= application.getBean("classService",ClassService.class)

苍枫露雨 | 园豆:1027 (小虾三级) | 2017-09-11 18:07

@苍枫露雨: 可以把实现类写出来吗?这个帖子拖了很久,也该结了。

小兵乙 | 园豆:112 (初学一级) | 2017-09-14 21:24

@苍枫露雨: ApplicationContext的源代码注释全是英文,看不懂....

小兵乙 | 园豆:112 (初学一级) | 2017-09-14 21:25

@小兵乙: 

        //得到上下文环境
        ApplicationContext application=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //得到内容容器
        ClassService cls= application.getBean("classService",ClassService.class);//转换为具体的接口
苍枫露雨 | 园豆:1027 (小虾三级) | 2017-09-15 15:09
其他回答(1)
0

你这里拿到的bean不都从ClassService派生出来的么?有什么不能转换的?如果派生类有特殊性需要额外支持的话那只能说明你接口定义不合理或者结构不正确。

Daniel Cai | 园豆:10424 (专家六级) | 2017-08-31 09:23

转换会报异常的

/**
     * 主方法
     * @param args
     */
    @SuppressWarnings("resource")
    public static void main(String[] args){
        //得到上下文环境
        ApplicationContext application=new ClassPathXmlApplicationContext("applicationContext2.xml");
        //得到内容容器
        ClassService cls=(ClassService) application.getBean("classService");//这里得到的bean是不确定的、可更换的,所以不能转换成具体的接口
        cls.save();
        
        ClassServiceImpl impl=(ClassServiceImpl) cls;
        System.out.println("i="+impl.getI());
    }
   

AOP是面向接口编程的,application.getBean()返回的是接口,不是实现类。

这是异常:

信息: Loading XML bean definitions from class path resource [applicationContext2.xml]
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy3 cannot be cast to com.yidu.aop.ClassServiceImpl
    at com.yidu.test.ClassTest.main(ClassTest.java:36)
注入:前置通知!
=================10
注入:后置通知!

支持(0) 反对(0) 小兵乙 | 园豆:112 (初学一级) | 2017-09-03 18:21
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册