aop的定义
在不修改源代码的情况下给程序动态添加一些额外的功能
aop的作用
采取横向抽取机制【即动态代理】取代传统的继承机制的重复性代码
aop大致步骤:
- 定义代理方法的接口
- 定义类实现接口
- 写一个Handler实现InovcationHandler接口的invoke方法
- 方法内部使用method.invoke(对象,构造参数)
- 在invoke上面写一个切面类的反射并且调用对应方法:
Class clazz = Class.forName("com.....");
Constructor constructor = clazz.getConstructor(参数对应的类名如(int.class));
constructor.setAccessible(true);
Object o = constructor.newInstance(<构造参数赋值>);
Method method = clazz.getMethod("方法名");
method.invoke(o,"方法参数");
6.也可以在代理invoke后执行对应的反射方法。
aop的应用场景:
日志记录、事务管理、权限验证、性能检测
aop使用的基本步骤:
首先是动态代理部分:
[先动态代理后在代理的invoke方法上下添加切面类的反射,然后可以IOC注入对象操作]
1. 定义一个所需要运行实现的方法的接口
package org.example;
public interface TollGateInter {
public float tollFee();
}
2. 定义一个类,该类实现该接口的方法
package org.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Car implements TollGateInter{
private float distance;
public void setDistance(float distance) {
this.distance = distance;
}
@Bean(name="Car")
public Car Car() {
return new Car();
}
public float tollFee() {
return (float) (distance*0.5);
}
}
3. 写一个动态代理实现invocationHandler接口的invoke方法
public class TestHandler implements InvocationHandler {
private Object object;
public TestHandler(Truck truck){
object = truck;
}
public TestHandler(Bus bus){
object = bus;
}
public TestHandler(Car car){
object = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// System.out.println("代理开始:~~~~");
// Class clazz = Class.forName("org.example.TollAspects");
// Constructor constructor = clazz.getConstructor();
// Object o = constructor.newInstance();
// Method method1 = clazz.getMethod("welcome",int.class);
// method1.invoke(o,2);
Object result = method.invoke(object,args);//arg为参数,object为要代理的对象
// Method method2 = clazz.getMethod("nextWelcome");
// method2.invoke(o);
// System.out.println("代理结束:~~~~");
return result;
}
}
4. 在主函数中实例化动态代理对象加入相关参数实现动态代理该方法
InvocationHandler invocationHandler = new TestHandler(new Car());
//可以在构造方法内放参数
TollGateInter car1 = (TollGateInter) Proxy.newProxyInstance(
Main.class.getClassLoader(),new Class[]{
TollGateInter.class
},invocationHandler);
其次是通过反射的方式在代理前后通过反射添加操作:
1. 定义一个切面类:
package org.example;
public class TollAspects {
public void welcome(int a){
System.out.println("欢迎光临收费站!"+a);
}
public void nextWelcome(){
System.out.println("欢迎下次再来!");
}
}
2. 在代理的invoke方法前后添加反射操作实现切面类的调用:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始:~~~~");
Class clazz = Class.forName("org.example.TollAspects");
Constructor constructor = clazz.getConstructor();
Object o = constructor.newInstance();
Method method1 = clazz.getMethod("welcome",int.class);
method1.invoke(o,2);
//-----------------代理前执行操作----------------
Object result = method.invoke(object,args);//--------------
//-----------------代理后进行操作---------------
Method method2 = clazz.getMethod("nextWelcome");
method2.invoke(o);
System.out.println("代理结束:~~~~");
return result;
}
作业题:
速公路收费系统针对不同的车辆收费也不一样,例如可能有如下的收费标准:七座以下的小汽车按里程收费,每公里0.5元,大巴车按可载乘员人数和里程收费,大于7人小于20人每公里1元,20人以上每公里1.2元。货车按载重量和里程收费,每吨每公里1元。每一种类型的车都通过编写一个车辆类来实现,简单起见,每种类型的车都有一个方法tollFee ,用来计算运费。
由于车辆类型和路费计算方法存在变数,收费站功能也存在今后进一步扩展的可能,要求设计并开发一个带有IOC和AOP功能的高速公路收费系统框架。
要求:1、开发一个收费程序TollGate类,该类至少具有一个收费charge功能,可以通过键盘输入的汽车类型和里程计算并输出过路费金额。车辆的类型可以是任意用户输入的类型,可通过一个可配置的IOC容器获取相关的车辆对象。对于新的车辆类型仅需要修改配置文件和编写相应的车辆类即可。
2、提供一个切面程序类,供今后进行功能扩展。系统可以通过一个可配置的AOP的方式对收费过程charge进行扩展。例如:可在收费前打印输出“欢迎光临xxx收费站,行驶里程数为xxxxx”,或在收费后打印输出文字“谢谢,祝旅途顺利!”。新功能扩展通过修改配置文件和切面程序类即可完成。
实现:
主函数:TollGate.calss
package org.example;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Scanner;
public class TollGate {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
InvocationHandler invocationHandler;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml"
);
while (true){
System.out.println("请输入车辆类型:(0:小汽车/1:大巴车/2:货车)");
int id = scanner.nextInt();
if(id == 0){
Car car = (Car) context.getBean("Car");
System.out.println("输入里程数:");
float dis = scanner.nextFloat();
car.setDistance(dis);
invocationHandler = new TestHandler(car);
} else if (id == 1) {
scanner.nextLine();
Bus bus = (Bus) context.getBean("Bus");
System.out.println("输入人数和里程数:");
String s = scanner.nextLine();
String[] s1 = s.split(" ");
bus.setNum(Integer.parseInt(s1[0]));
bus.setDistance(Float.parseFloat(s1[1]));
invocationHandler = new TestHandler(bus);
}else {
scanner.nextLine();
Truck truck = (Truck) context.getBean("Truck");
System.out.println("输入重量和里程数:");
String s = scanner.nextLine();
String[] s1 = s.split(" ");
truck.setWeight(Float.parseFloat(s1[0]));
truck.setDistance(Float.parseFloat(s1[1]));
invocationHandler = new TestHandler(truck);
}
TollGateInter car1 = (TollGateInter) Proxy.newProxyInstance(
Main.class.getClassLoader(),
new Class[]{TollGateInter.class},
invocationHandler
);
car1.tollFee();
}
}
}
代理:TestHandler.class
package org.example;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TestHandler implements InvocationHandler {
private Object object;
public TestHandler(Truck truck){
object = truck;
}
public TestHandler(Bus bus){
object = bus;
}
public TestHandler(Car car){
object = car;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class clazz = Class.forName("org.example.TollAspects");
Object o = clazz.newInstance();
Method method1 = clazz.getMethod("welcome",int.class);
method1.invoke(o,2);
Object result = method.invoke(object,args);
Method method2 = clazz.getMethod("nextWelcome");
method2.invoke(o);
return result;
}
}
切面类:TollAspects.class
package org.example;
public class TollAspects {
public void welcome(int a){
System.out.println("欢迎光临收费站!"+a);
}
public void nextWelcome(){
System.out.println("欢迎下次再来!");
}
}
Bean类:Bus.class【只写了一个】
package org.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Bus implements TollGateInter{
private int num;
private float distance;
public void setNum(int num) {
this.num = num;
}
public void setDistance(float distance) {
this.distance = distance;
}
@Bean(name = "Bus")
public Bus Bus() {
return new Bus();
}
public float tollFee(){
if(num>7 && num <20){
System.out.println("大巴车费用为:"+ distance);
return distance;
}else {
System.out.println("大巴车费用为:"+ distance*1.2);
return (float) (distance*1.2);
}
}
}
bean.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:mvc="http://www.springframework.org/schema/mvc" 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.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="org.example"/>
<aop:aspectj-autoproxy/>
</beans>