Spring AOP -- 10大细节之细节一:ioc容器中保存的是组件的代理对象

1、IOC容器中保存的是组件的代理对象

1.1、看看bean的真正类型

//看一下bean的类型是什么
System.out.println(bean);
//看看bean的真正类型
System.out.println(bean.getClass());

运行结果:
在这里插入图片描述
虽然看上去bean的类型是MyCalculaotr,但是实际上bean的真正类型是$Proxy13。
$Proxy13,这个类型肯定不是本类类型。

1.2、根据id拿组件

1.2.1、目标对象的类型,是其接口类型

//也可以根据id拿,ioc容器中没有指定id的话,id就是类名首字母小写
//注意:这里如果要强转的话,不能转换成MyCalculator,因为这个组件是Calculator类型的,代理对象和被代理对象唯一
//产生的关联就是他们实现了同一个接口,所以这里一定是他的接口类型
Object bean1 =  ioc.getBean("myCalculator");
System.out.println(bean1.getClass());

这里如果我们将Object类型换成Mycalculator的本类类型,会报错,如下

MyCalculator bean1 = (MyCalculator) ioc.getBean("myCalculator");
System.out.println(bean1.getClass());

运行结果:
在这里插入图片描述

必须将其强转成接口类型:

Calculator bean1 = (Calculator) ioc.getBean("myCalculator");
System.out.println(bean1.getClass());

运行结果:
在这里插入图片描述

1.2.2、cglib可以为没有接口的组件创建代理对象

1、将MyCalculator实现的接口去除
在这里插入图片描述
2、没有实现任何接口,怎么拿组件呢?

如果没有实现任何接口,在导入cglib的jar包的情况下,是可以为组件创建代理对象的,而且,根据类型拿组件的时候,其类型就是本类类型

public void test3(){
//MyCalculator没有实现任何接口,cglib也可以为其创建代理对象
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
MyCalculator bean2 = ioc.getBean(MyCalculator.class);
bean2.add(1,2);
System.out.println(bean2.getClass());
}

运行结果:
在这里插入图片描述
3、根据id拿组件
根据id也是可以拿到组件的,因为没有实现任何接口,所以在强转的时候,转换成他的本类类型即可。

1.2.3、源码

MyCalculator:

package com.fxp.impl;
import com.fxp.inter.Calculator;
import org.springframework.stereotype.Service;

@Service
public class MyCalculator /*implements Calculator*/ {
//在每个方法开始之前和结束之后都加入日志信息
//@Override
public int add(int i, int j) {
    int result = i+j;
    return result;
}

//@Override
public int sub(int i, int j) {
    int result = i-j;
    return result;
}

//@Override
public int mul(int i, int j) {
    int result = i*j;
    return result;
}

//@Override
public int div(int i, int j) {
    int result = i/j;
    return result;
}
}

Logutils:不用修改

package com.fxp.util;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
 * 如何将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
 * 1、导包
 * spring-aop-4.0.0.RELEASE.jar
 * spring-beans-4.0.0.RELEASE.jar
 * spring-context-4.0.0.RELEASE.jar
 * spring-core-4.0.0.RELEASE.jar
 * spring-expression-4.0.0.RELEASE.jar
 * commons-logging-1.1.3.jar
 *
 * Spring支持面向切面编程的基础版包:
 * spring-aspects-4.0.0.RELEASE.jar   这是基础版的,功能不是太强大
 *
 * Spring支持面向切面编程的加强版版包:(即使目标对象没有实现接口,也能创建动态代理)
 * com.springsource.net.sf.cglib-2.2.0.jar
 * com.springsource.org.aopalliance-1.0.0.jar
 * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
 */

//新的注解,@Aspect,这个注解就是告诉Spring这个类是切面类
@Aspect
//添加@component注解,将这个类加入到IOC容器中
@Component
public class LogUtils {

    /**
     * 告诉Spring每个方法什么时候运行
     * 5个通知注解
     * @Before:在目标方法运行之前运行;                          前置通知
     * @After:在目标方法运行结束之后运行                         后置通知
     * @AfterReturning:在目标方法正常返回之后运行                返回通知
     * @AfterThrowing:目标方法抛异常之后运行                     异常通知
	 * @Around:环绕                                             环绕通知
	 */

//这个方法想在执行目标方法之前运行,写切入点表达式
//切入点表达式写法:("execution(访问权限符 返回值类型 方法签名(方法的参数类型))")
//如果想在所有方法执行之前都先执行这个方法,只需要将方法签名改成:com.fxp.impl.MyCalculator.*(方法的参数类型)  即可
@Before("execution(public int com.fxp.impl.MyCalculator.*(int,int ))")
public static void logStart(){
    System.out.println("[xxx]开始执行.....它的参数是:xxx");
}
//这个方法想在目标方法正常执行结束之后运行
@AfterReturning("execution(public int  com.fxp.impl.MyCalculator.*(int,int))")
public static void LogReturn(){
    System.out.println("[xxx]正常执行完毕.....,结果是:xxx");
}
//这个方法想在目标方法出现异常的时候执行
@AfterThrowing("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogErr() {
    System.out.println("[xxx]出现异常:xxx");
}
//这个方法想在方法执行结束之后运行
@After("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogEnd() {
    System.out.println("方法最终执行完毕");
}
}

aop1.xml:没有变

<?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: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.xsd
   http://www.springframework.org/schema/context
   http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<context:component-scan base-package="com.fxp"></context:component-scan>
<!--开启基于注解的AOP功能:aop名称空间-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

Aoptest:

@Test
public void test3(){
//MyCalculator没有实现任何接口,cglib也可以为其创建代理对象
//class com.fxp.impl.MyCalculator$$EnhancerByCGLIB$$f8829780
//cglib帮我们创建好代理对象,在cglib里面会创建一个内部类,在这个内部类里面,实现了目标类里面所有的方法。
//有接口就用jdk创建代理对象,没有接口,就用cglib创建代理对象
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
MyCalculator bean2 = ioc.getBean(MyCalculator.class);
bean2.add(1,2);
System.out.println(bean2.getClass());
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值