前面又是讲代理,又是讲AOP;又是讲静态,又是讲动态;又是讲jdk aop,又是讲cglib;又是讲aspectj,又是讲其它。其实都是为了这一篇做铺垫。
spring aop 的简单例子
我们还是以一个简单的例子来观察一下spring aop究竟是长得什么样。
- pom文件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
需要引入aop模块和aspectj相关的包。
- xml文件
<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-4.0.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.xsd">
<bean id="weatherService" class="com.huangzp.test.service.impl.WeatherServiceImpl"/>
<!--必须开启bean扫描-->
<context:component-scan base-package="com.huangzp.test"/>
<!--必须开启aspectj,否则不会生效-->
<aop:aspectj-autoproxy />
</beans>
一定要开启<aop:aspectj-autoproxy />
- Java接口和实现
public interface IHelloService {
void sayHello();
}
@Service("helloService")
public final class HelloService implements IHelloService{
@Override
public void sayHello(){
System.out.println("hello world");
}
}
- 最重要的切面类
@Component
@Aspect
public class AopConfig {
@Before(value = "execution(* com.huangzp.test.aop.*.sayHello(..))")
public void sayHello(){
System.out.println("我是Aop config");
}
}
定义一个切面类,定义一个前置通知的切入点,可以看到它的语法和aspectj是如此的相似。
- 测试运行
public class AopMain {
public static void main(String[] args) {
//创建容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取personService的bean
IHelloService helloService = (IHelloService)applicationContext.getBean("helloService");
//调用方法
helloService.sayHello();
}
}
spring aop的底层实现
在Spring的底层,如果我们配置了代理模式,Spring会用ProxyFactoryBean为每一个Bean创建一个代理对象,如果是实现了接口的bean,那么创建的是JdkDynamicAopProxy;如果不是,则创建CglibAopProxy。
我们可以模拟一下实现:
- 模拟JdkDynamicAopProxy
//Java接口和实现类
public interface JDKHelloService {
void sayHello();
}
public class JDKHelloServiceImpl implements JDKHelloService{
@Override
public void sayHello() {
System.out.println("hello jdk aop");
}
}
//定义一个前置通知
public class AdviceBefore implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("我是前置通知");
}
}
//用ProxyFactoryBean来实验一下
public static void main(String[] args) {
//生成前置通知
Advice advice = new AdviceBefore();
//目标对象
JDKHelloService jdkHelloService = new JDKHelloServiceImpl();
//创建ProxyFactoryBean
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//设置目标对象,设置接口和添加通知
proxyFactoryBean.addAdvice(advice);
proxyFactoryBean.setInterfaces(JDKHelloService.class);
proxyFactoryBean.setTarget(jdkHelloService);
//生成代理并且运行
JDKHelloService helloService = (JDKHelloService)proxyFactoryBean.getObject();
helloService.sayHello();
}
我们在下面的helloService.sayHello();
设置断点并且进入,可以看到
![](https://img.haomeiwen.com/i1605579/9ec86f32b08d724a.png)
这个和我们之前的jdk aop 很像,我们设置保存代理文件得到的$proxy0和在jdk aop拿到的是一样的,在$proxy0中sayHello也是调用Proxy的InvocationHandler成员变量的invoke方法,那么这回什么实现了InvocationHandler?当然就是我们的JdkDynamicAopProxy。
- 模拟 CglibAopProxy
//目标对象,java实现类
public class CGLibHelloService {
public void sayHello(){
System.out.println("hello cglib aop");
}
}
//定义一个前置通知
public class AdviceBefore implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("我是前置通知");
}
}
//用ProxyFactorybean来测试一下
public static void main(String[] args) {
//生成前置通知
Advice advice = new AdviceBefore();
//目标对象
CGLibHelloService cgLibHelloService = new CGLibHelloService();
//创建ProxyFactoryBean
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
//设置目标对象和添加通知
proxyFactoryBean.addAdvice(advice);
proxyFactoryBean.setTarget(cgLibHelloService);
//生成代理并且运行
CGLibHelloService helloService = (CGLibHelloService)proxyFactoryBean.getObject();
helloService.sayHello();
}
我们在最下面的helloService.sayHello()设置短点并且进入,可以看到
![](https://img.haomeiwen.com/i1605579/d135852d3c39cfd7.png)
实际上还是用的ehancer动态创建的子类对象 和 方法拦截实现的cglib动态代理,只是这回之前的MyProxy代理类换成了CglibAopProxy。
网友评论