Spring(3)——EL,AOP

1 Spring EL

Spring EL可以使用运算符
例如:<property name = "username" value="#{1 == 1}"/>   返回true
常用数学公式几乎都能使用
PS:也可以使用三目运算符,例如:
<property name="username" value="#{1 == 1 ? false : true}"/ >

1.1 XML形式

<bean name="oneBean" class="com.cn.beans.OneBean">
    <property name="username" value="thinknovo"/>
</bean>
<bean name="twoBean" class="com.cn.beans.TwoBean">
    <property name="username" value="#{oneBean.username}"/>
    <property name="oneBean" value="#{oneBean}"/>
</bean>

在XML中,可以通过 #{ } 的形式获取对应的bean实例化对象或者bean对象中属性值。
(PS:注意这里的EL是Spring创造的,而不是我们原来使用的EL,我们原来的EL是隶属于JSF(java server face)。

1.2 注解形式

  1. XML文件中启用注解配置
    在XML中只需要添加一句这样的配置,所有bean的注册和注入全部通过注解方式完成。
<context:component-scan base-package="com.cn.aop" />

注意,启用上面的标签,需要在头文件中加入下面红色标注的新内容:
在这里插入图片描述
(PS:注意xsi:schemaLocation标签在idea中可能出现bug,会在执行测试的时候报找不到对应配置文件的错误,如果出现此问题,把xsi:schemaLocation标签内容写成一排,用空格隔开就可以正常使用了,然后再换成一行行的效果就没有问题了。)

  1. 扫描bean所在的包,如果在不同包,可以定位到父包就可以,比如上面还可以写为com.cn.beans,这样,beans下面所有的类和包都会被扫描检查是否存在,Bean(注解为@Component)并注册到 Spring 容器。
    接着开始注解bean对象
@Component("oneBean")
public class OneBean {
    @Value("think")
    private String username;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

然后再注解另一个bean对象

@Component("twoBean")
public class TwoBean {
    private OneBean oneBean;
    @Value("#{oneBean.username}")
    private String username;
    public OneBean getOneBean() {
        return oneBean;
    }
    public void setOneBean(OneBean oneBean) {
        this.oneBean = oneBean;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

注意第二个bean,在username属性中使用的是#{oneBean.username}注解方式。
PS:
1.这种注解方式是不需要set方法的,可以删除set方法测试一下。
2.spring的EL不管是XML还是注解方式都可以调用方法的,
例如:value="#{ oneBean.getUsername() }"/>
3.在EL中可以直接传入String并且调用它的方法,但是需要单引号,
例如:value ="#{‘think’.toUpperCase()}"/>

1.3 Spring EL使用List和Map

在Spring EL不能使用set,因为无序,无法基于key或者下标返回内容,所以只提供了List和Map的处理,例如:
value="#{oneBean.map [‘key’]}"/>
value="#{oneBean.list[0]}"/>
这里会首先调用OneBean对象的get方法得到对应的对象,然后通过key或者index拿到指定的值。

2 AOP 面向切面编程

2.1 概念

面向切面编程(AOP),是一种编程技术,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。
它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。
AOP 和 IOC 是补充性的技术,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上。当然,优势就是 Java 类不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。
AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。Spring AOP框架 用于在模块化方面的横切关注点。简单得说,它只是一个拦截器 拦截一些过程,例如,当一个方法执行,Spring AOP 可以劫持一个执行的方法,在方法执行之前或之后添加额外的功能。
在Spring AOP中,有 4 种类型(advices)支持:
1.通知(Advice)之前——某一个方法执行前运行
2.通知(Advice)返回之后——运行后,某一个方法返回一个结果
3.通知(Advice)抛出之后——运行方法抛出异常后
4.环绕通知——包含上述三种类型

学习参考博客:https://www.cnblogs.com/xrq730/p/4919025.html

2.2 AOP 底层原理

Spring 能够为容器中管理的对象生成动态代理对象,以前若要实现动态代理,需要自己调用Proxy.newProxyInstance()方法,来生成代理对象。
Spring 实现 AOP 底层采用了两种代理方式.分别是 JDK 的动态代理和 cglib 动态代理:

JDK 动态代理
被代理对象必须要求实现接口 才能产生代理对象,如果没有接口,将无法使用动态代理技术。 如果一个类实现了某接口,spring 会优先使用 JDK 动态代理技术为其产生代理对象。为 了保证每个对象都能生成代理对象,所以 Spring 又融入了第三方的代理技术。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
cglib 代理
可以对任何类生成代理,因为其代理的原理是对目标对象进行继承代理。如果目标对象被final 修饰,那么该类无法被 cglib 代理。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 名词解释

1 Joinpoint连接点

所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
目标对象中所有可以被增强方法,就是连接点。
在这里插入图片描述

2 Pointcut切入点

所谓切入点是指我们要对哪些连接点进行拦截的定义。
目标对象中,已经被增强的方法。
在这里插入图片描述

3 Advice通知/增强

所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
增强的代码
在这里插入图片描述

4 Target目标对象

代理的目标对象

5 Weaving植入

是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而AspectJ 采用编译期织入和类装在期织入。
把通知应用到连接点的过程:形成切入点的过程

6 Proxy代理

一个类被AOP植入增强后,就产生一个结果代理类
植入之后形成的代理对象
在这里插入图片描述

7 Aspect切面

切入点和通知的结合
在这里插入图片描述

2.4 demo

  1. spring_aop.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    <aop:aspectj-autoproxy />
    // 扫描两个包下的所有类 的注解
    <context:component-scan base-package="com.cn.aop" />
    <context:component-scan base-package="com.cn.service" />
</beans>
  1. SimpleAspect.java
@Component
@Aspect
public class SimpleAspect {
    @Pointcut("execution(* *service..*.*(..))")
    public void pointCut() {
        System.out.println("-------");
    }
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        System.out.println("切面执行后");
    }
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        //如果需要这里可以取出参数进行处理
        //Object[] args = joinPoint.getArgs();
        System.out.println("切面执行前");
    }
    @AfterReturning(pointcut = "pointCut()", returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint, Object returnVal) {
        System.out.println("执行后结果: "
                + returnVal);
    }
    @Around("pointCut()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("开始...");
        try {
            pjp.proceed();
        } catch (Throwable ex) {
            System.out.println("运行错误");
            throw ex;
        }
        System.out.println("运行结束");
    }
    @AfterThrowing(pointcut = "pointCut()", throwing = "error")
    public void afterThrowing(JoinPoint jp, Throwable error) {
        System.out.println("error:" + error);
    }
}
  1. PersonService.java
@Service
public class PersonService {
    public void addPerson(String personName) {
        System.out.println("add  " + personName);
    }
    public void deletePerson(String personName) {
        System.out.println("delete  " + personName) ;
    }
    public void editPerson(String personName) {
        System.out.println("edit  " + personName);
    }
}
  1. 测试类TestAop.java
public class TestAop {
    static ApplicationContext context;
    @BeforeClass
    static public void getXMl(){
        context = new ClassPathXmlApplicationContext("spring/spring_aop.xml");
    }
    @Test
    public void aop() throws Exception {
        PersonService personService = context.getBean(PersonService.class);
        String personName = "jwl";
        personService.addPerson(personName);
        personService.deletePerson(personName);
        personService.editPerson(personName);
        //((ClassPathXmlApplicationContext)context).close();
    }
}
发布了79 篇原创文章 · 获赞 7 · 访问量 1845

猜你喜欢

转载自blog.csdn.net/weixin_45044097/article/details/102731119