Spring:AOP详细解说

首先我们看看下面的思路

平常加日志的代码

在这里插入图片描述

  1. 日志不属于业务逻辑,却与业务混合在一起,业务组件添加了额外的日志责任
  2. 大量组件需要日志,哪一天不需要这样的日志,修改很大

解决方案1:使用代理

在这里插入图片描述
这样会导致代理类太多

解决方法2:动态代理

在这里插入图片描述

public class DynamicProxy{
    private Logger logger = Logger.getLogger(this.getClass().getName());
    private Object delegate;

    public Object bind(Object delegate) {
        this.delegate = delegate;
        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
                delegate.getClass().getInterfaces(),this::invoke);
    }
    public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {
        Object result;
        logger.log(Level.INFO, "method starts " + method);
        result = method.invoke(delegate, args);
        logger.log(Level.INFO, "method ends " + method);
        return result;
    }
}
public class test {
    public static void main(String[] args) {
       	DynamicProxy dynamicProxy= new DynamicProxy();
        IStudentService service = (IStudentService ) dynamicProxy.bind( new StudentService() );
        service.addStudent(new Student());
    }

}

什么是AOP

将系统中与业务无关的动作或服务(如:日志记录、事务处理、权限控制)设计为通用、不介入特定业务对象的、职责清楚的Aspect对象,这就是Aspect-oriented programming,即AOP编程

一丶几个概念

在这里插入图片描述

  1. 本例中StudentService本身的职责添加学生,却必须插入日志记录这样的与业务无关的动作,这样的动作AOP中称为横切关切点(Cross-cutting-concern)
  2. 使用代理对象将记录等与业务无关的动作或任务提出来,设计为一个服务对象,这样的对象称为切面(Aspect)
  3. Advice(通知)
    Aspect指的是一类服务,而Advice是这类服务当中具体的一个,如日志服务前面的DynamicProxy类(Advice与Aspect是具体与抽象的关系)
  4. Joinpoint(织入时机,连接点)
    在业务流程执行时织入Aspect对象的时机,如业务方法执行之前、之后、异常发生时
  5. Pointcut(切入点)
    Pointcut是一个定义,可以由它定义一些织入时机(Joinpoint)
  6. Target
    一个Advice被应用的对象或目标,如前面StudentService就是Advice DynamicProxy的target

二丶Spring AOP的写法

在这里插入图片描述

三个业务类
public class Student {
}
public interface IStudentService {
    public void addStudent(Student student);
}
public class StudentService  implements IStudentService{
    public  void addStudent(Student student){
        System.out.println("学生已添加");
    }
}

两个Advice类
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LogBeforeAdvice implements MethodBeforeAdvice {
    private Logger logger =  Logger.getLogger(this.getClass().getName());

    public void before(Method method, Object[] args, Object target)  {
        logger.log(Level.INFO, "method starts "+ method);
    }
}

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

public  class LogAfterAdvice implements AfterReturningAdvice {
    private Logger logger =  Logger.getLogger(this.getClass().getName());

    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) {
        logger.log(Level.INFO, "method ends "+ method);
    }
}
编织
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <beans>
        <bean id="LogBeforeAdvice"
              class="LogBeforeAdvice"/>
        <bean id="LogAfterAdvice"
              class="LogAfterAdvice"/>
        <bean id="StudentService"
              class="StudentService"/>


        <bean id="StudentServiceProxy"
              class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="proxyInterfaces">
                <value>IStudentService</value>
            </property>
            <property name="target">
                <ref bean="StudentService"/>
            </property>
            <property name="interceptorNames">
                <list>
                    <value>LogAfterAdvice</value>
                    <value>LogBeforeAdvice</value>
                </list>
            </property>
        </bean>
    </beans>

</beans>
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class test {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml");
        IStudentService StudentService =
                (IStudentService) context.getBean("StudentServiceProxy");
        StudentService.addStudent(new Student());
    }

在这里插入图片描述

三丶实战

  1. 使用AspectJ注解,毕竟太麻烦了写配置文件
  2. 结合Spring IOC和Spring MVC
    在这里插入图片描述
三个业务类
public class Student {
}
public interface IStudentService {
    public void addStudent(Student student);
}
@Component
public class StudentService  implements IStudentService{
    public  void addStudent(Student student){
        System.out.println("学生已添加");
    }
}

一个Advice类
@Aspect
@Component
public class LogAdvice{
    private Logger logger =  Logger.getLogger(this.getClass().getName());

    @Before("execution(* StudentService.addStudent(..))")
    public void before()  {
        logger.log(Level.INFO, "method starts ");
    }
    @After("execution(* StudentService.addStudent(..))")
    public void afterReturning() {
        logger.log(Level.INFO, "method ends ");
    }
}
一个Controller类
@Controller
@RequestMapping("/o")
public class TestController {
    @Autowired
    private IStudentService studentService;
    @RequestMapping("/ok")
    public  String run() {
        studentService.addStudent(new Student());
        return "index";
    }

}
编制

我们使用注解帮我们编制,那么我们只需要扫描

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 			http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="test"/>
    <aop:aspectj-autoproxy />
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

改一下web.xml下面部分

 <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
   </servlet-mapping>

接下来运行网页,输入网址

http://localhost:8080/untitled7_war_exploded/o/ok

结果如下

在这里插入图片描述

发布了124 篇原创文章 · 获赞 92 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42146775/article/details/103206895
今日推荐