一. 首先建立一个基于spring的maven工程
1.项目目录如下:
2.pom.xml文件引入spring的核心包,aop包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tp.demo</groupId>
<artifactId>spring</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
3.根据上图所示建立好相应的包,类,接口
(1)建立实体类User
package com.tp.aop.entity;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 11:41
* @Version: 1.0
*/
public class User {
private int id;
private String name;
public User() {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
(2)建一个UserService的接口,并且实现UserService接口
UserService.java
package com.tp.aop.service;
import com.tp.aop.entity.User;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 11:40
* @Version: 1.0
*/
public interface UserService {
String printUser(User user);
}
UserServiceImpl.java
@Service("userService")注解是告诉Spring,当SpringIOC容器要创建UserServiceImpl的的实例时,bean的名字必须叫做"userService"
package com.tp.aop.service.impl;
import com.tp.aop.entity.User;
import com.tp.aop.service.UserService;
import org.springframework.stereotype.Service;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 11:42
* @Version: 1.0
*/
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public String printUser(User user) {
System.out.println(user);
return user.toString();
}
}
(3)创建一个Controller
@Controller 用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法。通俗来说,被Controller标记的类就是一个控制器,这个类中的方法,就是相应的动作。
在控制类中调用一下UserSerice
package com.tp.aop.controller;
import com.tp.aop.entity.User;
import com.tp.aop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 11:39
* @Version: 1.0
*/
@Controller
public class UserController {
@Autowired
private UserService userService;
public String print(int id, String name) {
User user = new User();
user.setId(id);
user.setName(name);
return userService.printUser(user);
}
}
(4)创建一个切面类,用于计算UserService接口中printUser方法被调用前后的耗时
@Component注解泛指组件,将该类添加到springIOC容器中。
@Aspect注解表名这是一个切面类
package com.tp.aop.aspect;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 16:36
* @Version: 1.0
*/
@Component
@Aspect
public class MyAspect {
private long beforeTime;
private long afterTime;
@Pointcut("execution(* com.tp.aop.service.impl.UserServiceImpl.printUser(..))")
public void pointCut() {
}
@Before("pointCut()")
public void before() {
beforeTime = System.currentTimeMillis();
System.out.println("before---------------"+ beforeTime);
}
@After("pointCut()")
public void after() {
afterTime = System.currentTimeMillis();
System.out.println("after----------------" + afterTime);
}
@AfterReturning("pointCut()")
public void afterReturning() {
System.out.println("耗时:" + (afterTime - beforeTime));
}
}
(5)创建一个启动类Application
@ComponentScan("com.tp.aop")注解扫包,@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
@EnableAspectJAutoProxy注解启用aop功能
package com.tp.aop;
import com.tp.aop.entity.User;
import com.tp.aop.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @Author: pengtao
* @Date: 2019/5/8/0008 11:55
* @Version: 1.0
*/
@ComponentScan("com.tp.aop")
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
ApplicationContext app = new AnnotationConfigApplicationContext(Application.class);
UserService userService = (UserService)app.getBean("userService");
User user = new User(1, "lucky");
userService.printUser(user);
System.out.println(userService);
}
}
运行,结果如下,发现aop功能生效了
二.分析aop底层实现,调试跟踪。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler
接口和Proxy
类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final
,那么它是无法使用CGLIB做动态代理的。
1.我们在Application启动类中加入断点调试一把,看看这个userService对象是什么?
发现userService对象是$Proxy@1887 这个类已经被代理了。使用了jdk的动态代理
如果UserService不实现接口的话,直接是个类就是cglib代理了。
这里我们吧代码里的UserService实现类改一下改为不实现接口
把controller用到UserService的地方和Application用到UserService的地方改一下
调试一把看看userService是什么东西
已经是cglib代理的类了,之后会把这些代理的类给导出来,看看是啥。后续。
-----------------------------明天再写,怎么调试跟踪在什么地方被代理了,累了。。。。。。