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());
}