1. 什么是AOP?
AOP(面向对象编程),它是对OOP(面向对象编程)的一种补充和扩展
例:
//需要手动处理事务(在这方法之前做一些操作:开启事务setAutoCommit(false);)
public void add(){
//添加方法
}
//在这个方法执行之后做一些操作(提交、回滚事务)
这也就意味着所有的DML操作方法都需要手动处理这些事务的问题,重复代码很多(会写很多try...catch)
2. 在你的框架项目中有没有使用过AOP?
因为Service要处理事务,我们通过@Service注解完成对事物的处理
因为@Service是Spring中的注解,所以会使用Spring中的AOP在某个方法前后做一些操作对事务进行处理
3. AOP的底层是基于什么设计模式来实现的
AOP基于动态代理来实现的,动态代理的核心思想就是通过Java中的反射获取切入点(PointCut),在切入点(方法)前后做一些操作
动态代理会分为:
1. JDK的动态代理
2. Spring提供好的动态代理
4. 代理模式
核心思想:
引入一个代理对象来控制对目标对象的访问
代理对象和目标对象实现相同的接口,使得客户端可以通过代理对象间接地访问目标对象
代理对象负责处理客户端的请求,并在必要时将请求转发给目标对象
在这个过程中,代理对象可以添加额外的逻辑,如权限检查、缓存、日志记录等
主要角色:
抽象主题(Subject):定义了代理对象和目标对象的共同接口,在Java中通常是一个接口或抽象类
目标对象(RealSubject):定义了代理对象所代表的真实对象,是业务逻辑的具体执行者
代理对象(Proxy):持有对目标对象的引用,并实现了与目标对象相同的接口,在方法调用前后进行额外操作
1)静态代理
/**
* 静态代理的特点:
* 需要手动编写代理类,工作量较大(因为代理类也要实现接口,所以在重写方法的时候需要在调用方法的前后都要做一些操作)。
* 目标对象必须实现接口。
* 代理类和目标类的关系在编译时就确定了,无法动态改变。
*/
public class CompanyProxy implements SuperMarketAction {
private SuperMarketImpl superMarket;//目标对象
//定义结构器用于初始化目标对象
public CompanyProxy(SuperMarketImpl superMarket){
this.superMarket = superMarket;
}
@Override
public void deliver() {
System.out.println("代理类调用方法之前要做的操作");
superMarket.deliver();
System.out.println("代理类调用方法之后要做的操作");
}
public static void main(String[] args) {
SuperMarketImpl superMarket = new SuperMarketImpl();
CompanyProxy companyProxy = new CompanyProxy(superMarket);
companyProxy.deliver();
}
2)动态代理
Java的动态代理机制是基于反射实现的,通过使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现动态代理
(1)JDK的动态代理
代理类:
/**
* JDK的动态代理
* 定义一个接口,作为目标接口。
* 创建一个InvocationHandler接口的实现类,该类负责处理方法调用并执行额外的操作。
* 使用Proxy类的静态方法newProxyInstance()生成代理对象,同时指定目标对象和InvocationHandler。
* 客户端使用代理对象来访问目标对象的方法。
*/
public class CompanyInvocationHandler implements InvocationHandler {
private SuperMarketAction superMarket;
public CompanyInvocationHandler(SuperMarketAction superMarket){
this.superMarket = superMarket;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("使用动态代理在调用某个方法前要做的操作");
Object result = method.invoke(superMarket,args);//通过反射获取切入点(接口中的方法)
System.out.println("使用动态代理在调用某个方法后要做的操作");
return result;
}
//生成代理对象
// public static Object newProxyInstance(ClassLoader loader,
// Class<?>[] interfaces,
// InvocationHandler h)
// throws IllegalArgumentException
//以上方法的参数说明:
//ClassLoader loader 被代理对象的类的加载器
//Class<?>[] interfaces 被代理对象的接口列表
//InvocationHandler h 动态代理的核心处理程序
public Object createProxy(){
return Proxy.newProxyInstance(superMarket.getClass().getClassLoader(),superMarket.getClass().getInterfaces(),this);
}
测试类:
public class TestDyProxy {
public static void main(String[] args) {
SuperMarketAction superMarketAction = new SuperMarketImpl();
CompanyInvocationHandler invocationHandler = new CompanyInvocationHandler(superMarketAction);
SuperMarketAction action = (SuperMarketAction) invocationHandler.createProxy();
action.deliver();
action.test();
}
}
(2)cglib的动态代理(Spring用的动态代理就是cglib)
代理类:
/**
* cglib的动态代理(Spring用的动态代理就是cglib)
*/
public class MethodHandler implements MethodInterceptor {
/**
*
* @param o 被代理对象
* @param method 被拦截的方法
* @param objects 参数
* @param methodProxy 用于调用原始的方法
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Spring CGLIB动态代理调用方法之前要做的操作");
Object result = methodProxy.invokeSuper(o,objects);//获取切入点
System.out.println("Spring CGLIB动态代理调用方法之后要做的操作");
return result;
}
}
测试类:
public class TestCglib {
public static void main(String[] args) {
//创建一个cglib的增强对象
Enhancer enhancer = new Enhancer();
//设置被代理类
enhancer.setSuperclass(SuperMarketImpl.class);
//设置代理类方法的拦截器
enhancer.setCallback(new MethodHandler());
//创建代理对象
SuperMarketAction superMarketAction = (SuperMarketAction) enhancer.create();
superMarketAction.deliver();
}
}
3)JDK的动态代理和cglib的区别
(1)JDK的动态代理核心处理类要实现InvocationHandler并重写invoke方法,之后通过调用Method对象中的invoke方法来调用目标对象的方法
(2)Cglib的动态代理核心的处理类要实现MethodInterceptor并重写intercept,之后通过调用methodProxy.invokeSuper(o,objects)来拦截目标对象中的方法。
(3)使用Cglib的动态代理生成的代理对象可以使用接口也可以使用实现类,而JDK的动态代理生成的代理对象只能使用接口
5. Spring中AOP在项目中除了处理事务,还有哪些应用呢?
常用的标签都有哪些?
1)AOP除了事务处理还可以处理权限以及对日志的处理
2)通过配置文件来实现AOP动态代理
配置文件:
<bean id="eddie" class="com.foreknow.aop.Instrumentailst">
<property name="instrument">
<bean class="com.foreknow.aop.Guitar"></bean>
</property>
<property name="song" value="song lalala~"></property>
</bean>
<!-- 配置切面 -->
<bean id="audience" class="com.foreknow.aop.Audience"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 配置切面:在切入点之前或之后要调用的方法 -->
<aop:aspect ref="audience">
<!-- 配置切入点 -->
<!--
expression 当方法被执行的时候才会执行这个表达式
*表示方法的返回值类型为任意类型
..表示任意类型
-->
<aop:pointcut id="performance" expression="execution(* com.foreknow.aop.Performer.perform(..))"/>
<!-- 表演之前 -->
<aop:before pointcut-ref="performance" method="takeSeats"></aop:before>
<aop:before pointcut-ref="performance" method="closeOffPhone"></aop:before>
<!-- 表演之后 -->
<aop:after method="appland" pointcut-ref="performance"></aop:after>
<aop:after method="backMoney" pointcut-ref="performance"></aop:after>
</aop:aspect>
</aop:config>
测试类:
public class TestAop {
public static void main(String[] args) {
//解析配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-idol.xml");
Performer performer = (Performer) context.getBean("eddie");//Instrumentailst对象
performer.perform();
}
}