Java学习日志——AOP

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();
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值