AOP概念
- (1)AOP(Aspect Oriented Programming)是
面向切面编程
。
就是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码,提高开发效率,维护方便
本质上是生成了一个新的类,叫做代理类。
- (2)动态代理和静态代理
静态代理
:静态代理需要你手动实现代理类对象。通过和被代理类实现相同的接口的方式,在代理类中调用被代理类的方法,在代理类中编写需要增强的代码。
动态代理
:由机器自动的为你生成代理类对象。你只需要定义被代理类对象,被代理类对象实现的接口。 - (3)AOP对程序的扩展方式采用动态代理的方式. (
JDK动态代理
和Cglib动态代理
两种方式)
AOP 的实现方式:动态代理
- (1)JDK的动态代理
》Proxy类的方法
Proxy类的静态方法可以创建代理对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
》三个参数
参数1:ClassLoader loader 类加载器 , 用来加载代理对象
参数2:Class<?>[] interfaces 目标类的字节码对象数组. 因为代理的是接口,需要知道接口中所有的方法
参数3:InvocationHandler h 执行句柄, 代理对象处理的核心逻辑就在该接口中
》基于接口的动态代理
提供者:JDK官方的Proxy类
要求:被代理类最少实现一个接口
案例一:老总吃饭
》老总接口
public interface ILaoZong {
void eat();
void sleep();
}
》老总实现类
public class LaoZong implements ILaoZong{
@Override
public void eat() {
System.out.println("吃饭饭");
}
@Override
public void sleep() {
System.out.println("睡觉觉");
}
}
》秘书类(给老总吃睡添加服务),
public class MiShu {
public void laiBeiJiu(){
System.out.println("laiBeiJiu");
}
public void laiGenYan(){
System.out.println("laiGenYan");
}
}
》TestJdkProxy
public class TestJdkProxy {
public static void main(String[] args) {
//jdk动态代理
//创建被代理类对象
LaoZong laoZong = new LaoZong();
//创建添加增强方法的对象
MiShu miShu = new MiShu();
//创建一个代理类,创建该类的对象
//1、和被代理对象使用相同的类加载器, 用来加载代理对象,
ClassLoader classLoader = LaoZong.class.getClassLoader();
//2、目标类的字节码对象数组. 因为代理的是接口,需要知道接口中所有的方法。和被代理对象具有相同的行为。实现相同的接口。
// Class[] interfaces = LaoZong.class.getInterfaces();
Class[] interfaces = new Class[]{
ILaoZong.class};
//3、执行句柄, 即如何代理,代理对象处理的核心逻辑就在该接口中
InvocationHandler handler = new InvocationHandler() {
//proxy:代理对象的引用。不一定每次都用得到
//method:当前执行的方法对象,即你要增强的原方法
//args:执行方法所需的参数,即要给原方法传入的参数
//返回值 Object:当前执行方法的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调 laibeijiu()
miShu.laiBeiJiu();
//执行 laoZong.eat(); 或者 laoZong.sleep();方法
Object returnValue = method.invoke(laoZong,args);
//调 laiGenYan()
miShu.laiGenYan();
return returnValue;
}
};
//调用增强后的方法
ILaoZong iLaoZong = (ILaoZong) Proxy.newProxyInstance(classLoader,interfaces,handler);
iLaoZong.eat();
iLaoZong.sleep();
}
}
》运行结果
laiBeiJiu
吃饭饭
laiGenYan
laiBeiJiu
睡觉觉
laiGenYan
案例二:日志系统
增强Dao类中的方法,在它们调用之后打印日志。
》IPersonDao2
public interface IPersonDao2 {
void add(Person person);
void update(Person person);
void delete(int id);
}
》PersonDao2
public class PersonDao2 implements IPersonDao2{
@Override
public void add(Person person) {
System.out.println("执行数据库的insert");
}
@Override
public void update(Person person) {
System.out.println("执行数据库的update");
//睡3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void delete(int id) {
System.out.println("执行数据库的删除");
}
}
》Demo02
//增强内容:日志打印消息 和 计算调用时间
public class Demo02 {
public static void main(String[] args) {
//创建日志类对象
Logger logger = LoggerFactory.getLogger(PersonDao2.class);
//1.创建被代理对象
IPersonDao2 personDao2 = new PersonDao2();
System.out.println("增强之前的方法----------");
Person person = new Person("jack","1234");
personDao2.update(person);
//2.开始代理增强方法
//三个参数
ClassLoader classLoader = personDao2.getClass().getClassLoader();
Class<?>[] interfaces = personDao2.getClass().getInterfaces();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//开始时间
long start = System.currentTimeMillis();
//调用原来的方法
Object returnVal = method.invoke(personDao2, args);
//用时 = 结束时间 - 开始时间
long time = System.currentTimeMillis() - start;
logger.debug("方法名"+method.getName()+" 参数"+ Arrays.toString(args) + " 运行时间" + time);
return returnVal;
}
};
//3.创建代理类对象,调用增强后的方法
IPersonDao2 personDao = (IPersonDao2) Proxy.newProxyInstance(classLoader, interfaces, handler);
System.out.println("增强之后的方法-----------");
// personDao.add(person);
personDao.update(person);
// personDao.delete(1);
}
}
》运行结果
增强之前的方法----------
执行数据库的update
增强之后的方法-----------
执行数据库的update
DEBUG [main] - 方法名update 参数[Person{
username='jack', password='1234'}] 运行时间3000