Java spring详解 (学习总结)

配置JavaSpring

使用maven配置:在pom.xml文件中输入以下依赖

   <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.18</version>
        </dependency>
    </dependencies>

配置applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="stu" class="POJO.Student">
        <property name="name" value="John"></property>
        <property name="age" value="18"></property>
        <property name="id" value="1"></property>
    </bean>
</beans>

创建Student类 

/注意包名对应
public class Student {
    private String name;
    private int age;
    private int id;

    public Student(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    //省略无参构造函数,getter和setter方法
}

有些Idea不会自动配置module-info文件,可以根据需要配置,不然会显示Error creating bean with name 'stu' defined in class path resource [applicationContext.xml]: Instantiation of bean failed;

测试:如果可以正常跑说明Spring配置成功! 

package test;
import POJO.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest {
    public static void main(String[] args) {
        //读取配置文件
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student stu = applicationContext.getBean("stu", Student.class);
        System.out.println(stu);
    }
}

IOC 

IOC(概念)

IOC中文名是控制反转。

用最简单的话来说就是:解耦合。

把对象的创建,对象之间调用的过程都交给Spring管理

IOC(底层原理)

(1)xml解析、工厂设计模式

(2)反射

正常情况下我们要先声明创建对象,才可以访问其字段和方法。耦合度极高!

IOC底层原理

使用工厂设计模式:就可以先在工厂中创建对象,再将对象传给需要的地方。(初步实现耦合)再xml解析出需要的类,使用反射进一步解耦合。

(1)使用xml配置文件,配置创建的对象

    <bean id="stu" class="POJO.Student">
        <property name="name" value="John"></property>
        <property name="age" value="18"></property>
        <property name="id" value="1"></property>
    </bean>

(2)有service类和dao类,创建工厂类

此时如果要修改声明的类,只用修改xml文件即可。

此时的耦合度已经进一步降低!! 

IOC(的接口)

(1)IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。

(2)Spring提供IOC容器实现的两种方式

          - BeanFactory:加载xml配置文件的时候不会创建对象,getBean的时候才创建对象

          - ApplicationContext:BeanFactory接口的子接口,功能更加强大。对象的创建是在服务器启动时,使用的时候已经创建好了。

(3)ApplicationContext接口有实现类:

         - FileSystemXmlApplicationContext( 文件磁盘路径 )

         - ClassSystemXmlApplicationContext( src下类路径 )

IOC操作bean管理

Bean管理指的是两个操作:

(1)创建对象

(2)注入属性

Bean管理的操作:

        基于xml配置文件方式实现

        *id是一个标识,标识这个bean

        *class填写全类名

·第一行使用默认使用无参构造方法构造对象

    <bean id="stu" class="POJO.Student"></bean>
DI:是IOC的具体实现。注入属性,在创建对象的基础之上。

第一种注入方式:通过set方法注入

第二种注入方式:通过有参构造函数注入
    <bean id="stu" class="POJO.Student">
        <property name="name" value="John"></property>
        <property name="age" value="18"></property>
        <property name="id" value="1"></property>
    </bean>

第一种方式⬆️

    <bean id="stu2" class="POJO.Student">
        <constructor-arg name="name" value="Willion"></constructor-arg>
        <constructor-arg name="id" value="2"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
    </bean>

第二种方式⬆️

IOC操作Bean管理(xml注入其他类型属性)

1.null值

    <bean id="stu" class="POJO.Student">
        <property name="id">
            <null/>
        </property>
    </bean>

2.属性值包括特殊符号

<![CDATA[<<Lion>>]]> 黄色部分可以写入特殊字符

或者转译<(&lt;) >(&gt;)

    <bean id="stu" class="POJO.Student">
        <property name="name">
            <value>
                <![CDATA[<<Lion>>]]>
            </value>
        </property>
    </bean>

注入属性-外部bean

(1)创建两个service类和dao类

(2)在service调用dao里面的方法

public class StudentDaoImpl implements StudentDao{

    @Override
    public void update() {
        System.out.println("service runs");
    }
}
public class StudentService {
    public void read(){
        System.out.println("Students are reading");
    }
}
public interface StudentDao {
    void update();
}

(3)在Spring配置文件中进行配置( 注意ref放的是对象id )

        注意两点:

        1.bean中class不可以写入接口,所以只可以写入实现接口的类

        2.本写法分别调用了两个类的无参构造方法并且调用了StudentService的set方法

<!--service和dao对象创建-->
    <!-- 
    ref里面放的是该beans里面配置对应id的对象
    将外部bean注入进来
    -->
    <bean id="StudentService" class="service.StudentService">
        <property name="studentDao" ref="StudentDao"></property>
    </bean>
    
    <bean id="StudentDao" class="dao.StudentDaoImpl"></bean>
    

注入属性-内部bean和级联赋值 

1、内部bean

(1)一对多关系:学生和老师

(2)在实体类中以对象的形式表示一对多

                即在学生类(多)中创建字段老师(一)

(3)在xml文件中进行配置

    <bean id="Student" class="POJO.Student">
        <property name="id" value="3"></property>
        <property name="name" value="Garson"></property>
        <property name="age" value="20"></property>
        <property name="teacher">
            <bean id="teacher" class="POJO.Teacher">
                <property name="name" value="Nadine"></property>
                <property name="subject" value="speaking"></property>
            </bean>
        </property>
    </bean>

(4)进行测试

    @Test
    public void testManyOne(){
        //根据配置文件执行相关操作
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean2.xml");
        //获取指定id号的对象
        Student student = applicationContext.getBean("Student",Student.class);
        //进行操作
        System.out.println(student+" - "+student.getTeacher());
    }
Spring的执行步骤

1、通过ApplicationContext去执行相应的配置文件

此时根据文件中写入的逻辑创建对象

2、通过getBean得到相应对象

测试结果:

 2、级联方式

    <bean id="Student2" class="POJO.Student">
        <property name="id" value="3"></property>
        <property name="name" value="Garson"></property>
        <property name="age" value="20"></property>
        <!--对应下面的bean-->
        <property name="teacher" ref="teacher"></property>
        <property name="teacher.subject" value="speaking"></property>
        <property name="teacher.name" value="Betty"></property>
    </bean>
    <bean id="teacher" class="POJO.Teacher"></bean>

IOC操作Bean管理(xml注入集合属性) 

public class Emp {
    private List<String> list;
    private String[] array;
    private Map<String,String> map;
    // getter、setter、toString方法和构造函数
}

1、注入数组类型属性 2、注入List集合类型属性 3、注入Map集合类型属性

<bean id="Emp" class="POJO.Emp">
        <!--数组类型注入-->
        <property name="array">
            <array>
                <value>content1</value>
                <value>content2</value>
                <value>content3</value>
            </array>
        </property>
        <!--list类型注入-->
        <property name="list">
            <list>
                <value>content1</value>
                <value>content2</value>
                <value>content3</value>
            </list>
        </property>
        <!--map类型注入-->
        <property name="map">
            <map>
                <entry key="1" value="content1"></entry>
                <entry key="2" value="content2"></entry>
                <entry key="3" value="content3"></entry>
            </map>
        </property>
    </bean>

添加两个细节:

1、写入的对象不是String类型怎么办

//Emp中的List2存放Student类的List    
<bean id="Emp" class="POJO.Emp">
        <property name="list2">
            <list>
                <ref bean="student1"></ref>
                <ref bean="student2"></ref>
                <ref bean="student3"></ref>
            </list>
        </property>
    </bean>
    
    <bean id="student1" class="POJO.Student"></bean>
    <bean id="student2" class="POJO.Student"></bean>
    <bean id="student3" class="POJO.Student"></bean>

2、想把某一字段提取出来当成该类的static类字段怎么办

(1)在Spring配置文件中引入名称空间util

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    
    
</beans>

(2)使用util标签完成List集合注入

          ref全称reference,可以引用其他的bean标签。

<!--1、创建list并且提取-->
    <util:list id="StudentList">
        <ref bean="student1"></ref>
        <ref bean="student2"></ref>
        <ref bean="student3"></ref>
    </util:list>
<!--2、使用-->
    <bean id="emp" class="POJO.Emp">
        <property name="list2">
            <ref bean="StudentList"></ref>
        </property>
    </bean>
</beans>

IOC操作Bean管理(FactoryBean) 

1、Spring有两种类型bean,一种普通bean,一种FactoryBean。

2、普通bean定义类型和返回类型一样,FactoryBean可以不一样。

具体做法

(1)创建一个myBean类作为FactoryBean实现接口

          重写getObject方法

package factorybean;
import POJO.Student;
import org.springframework.beans.factory.FactoryBean;
public class myBean implements FactoryBean<Student>{

    @Override
    public Student getObject() throws Exception {
        return new Student();
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

(2)在配置文件中定义myBean类

  <bean id="myBean" class="factorybean.myBean"></bean>

(3)测试

    @Test
    public void testBeanFactory(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean4.xml");
        Student mybean = applicationContext.getBean("myBean", Student.class);
        System.out.println(mybean);
    }

配置文件中是myBean类但实际返回值是Student类

IOC容器Bean管理(bean的作用域) 

1、在Spring里面默认情况下bean是一个单实例对象​​​​​​​

Student mybean1 = applicationContext.getBean("myBean", Student.class);
        Student mybean2 = applicationContext.getBean("myBean", Student.class);
        System.out.println(mybean1+"-"+mybean1.SuperToString());
        System.out.println(mybean2+"-"+mybean2.SuperToString());

 (输出的内存地址是相同的)

2、在Spring里面可以设置创建的bean实例是一个单实例还是多实例

(1)Spring配置文件中有属性(scope)用于设置单实例、多实例

(2)scope的值:

        第一个值:默认值,singleton,表示是单实例对象

        第二个值:prototype,表示是多实例对象

IOC操作Bean管理(bean生命周期)

1、Bean的生命周期

2、Bean生命周期

(1)创建Bean实例(通过构造器)

(2)为bean的属性设置值和对其他bean的引用(调用set方法)

(3)调用了bean的初始化方法(需要进行配置)

    public void initMethod(){
        System.out.println("值行了initMethod方法");
    }
    <bean id="Student" class="POJO.Student" init-method="initMethod">

(4)bean可以使用了(对象获取到了)

(5)当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

    public void destroyMethod(){
        System.out.println("值行了destroyMethod方法");
    }
    <bean id="Student" class="POJO.Student" destroy-method="destroyMethod">
    @Test
    public void testBeanFactory(){
        //根据配置文件执行相关操作
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean4.xml");
        //获取指定id号的对象
        Student mybean1 = applicationContext.getBean("myBean", Student.class);
        Student mybean2 = applicationContext.getBean("myBean", Student.class);
        //进行操作
        System.out.println(mybean1+"-"+mybean1.SuperToString());
        System.out.println(mybean2+"-"+mybean2.SuperToString());
        //手动销毁
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }

调用 ((ClassPathXmlApplicationContext)applicationContext).close();

执行销毁,并执行定义的destroyMethod方法

3、Bean的后置处理器(BeanPostProcessor接口)

在Spring调用了set方法和初始化方法之后,会将Bean实例传递给Bean后置处理器的方法

(1)创建类,实现BeanPostProcessor接口

public class MyBeanPost implements BeanPostProcessor {
//Bean创建之后调用set方法后执行
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
//Bean初始化之后执行
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

(2)Spring会为所有Bean都添加后置处理器处理

IOC操作Bean管理(xml自动装配)

什么是自动装配:根据属性类型和属性名称,Spring自动完成属性注入

(1)根据属性名称自动注入

    <!--
    autowire两个常用的值
    byName根据属性名称注入。注入值bean的id值和类属性名一致
    -->
    <!--private Teacher teacher;-->
    <bean id="Student" class="POJO.Student" autowire="byName"></bean>
    <bean id="teacher" class="POJO.Teacher"></bean>

(2)根据属性类型自动注入

    <bean id="Student" class="POJO.Student" autowire="byType"></bean>
    <bean id="teacher" class="POJO.Teacher"></bean>

根据类型自动注入相同类型的Bean不可以定义多个

因为Spring无法确定用哪个Bean注入

IOC操作Bean管理(外部属性文件)

1、引入外部属性文件配置数据库连接池

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
//命名空间填充xmlns:context="http://www.springframework.org/schema/context"    

    <!--引入外部文件-->
    <context:property-placeholder location="jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverclass}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
username=root
password=wuguixin
url=jdbc:mysql://localhost:3306/Flight
driverclass=com.mysql.cj.jdbc.Driver

IOC操作Bean管理(基于注解方式)

1、格式: @注解名称(属性名=属性值,属性名称=属性值)

      位置:作用在类、方法、属性上面

      目的:简化xml配置

2、Spring针对Bean管理中创建对象提供注解

(1)@Component             普通注解

(2)@Service                    用在业务逻辑层

(3)@Controller                用在WEB层

(4)@Repository               用在持久层上

*上面四个注解功能是一致的,都可以用来创建bean实例

3、基于注解方式实现对象创建

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

   

    <!--
    1、开启组件扫描,多个包用逗号隔开
    2、扫描包上层目录
    -->
    <context:component-scan base-package="POJO"></context:component-scan>
package POJO;

import org.springframework.stereotype.Component;

//value属性值可以省略(如果不写默认值就是其名称,首字母小写),但一般都要写!
@Component(value = "User") //相当于<bean id="User" class=""/>
public class User {
    public void method(){
        System.out.println("调用User的Method方法");
    }
}
    @Test
    public void testAutoWire(){
        //根据配置文件执行相关操作
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean5.xml");
        //获取指定id号的对象
        Student mybean = applicationContext.getBean("Student", Student.class);
        //进行操作
        System.out.println(mybean);
        //手动销毁
        ((ClassPathXmlApplicationContext)applicationContext).close();
    }

测试结果:

4、开启组件扫描中的细节配置

(1)包内全扫描

    <context:component-scan base-package="POJO"></context:component-scan>

(2)自定义过滤器

                                                    ​​​​​​​  · type = "annotation"注解扫描

  · expression="xxx.Controller"只会扫描带Controller注解的类

(3)哪些不扫描

IOC操作Bean管理(注解方式注入属性)

(1)@Autowire - 根据属性名进行自动装配

           不需要添加set方法

           添加属性注解@Autowire

           bean对应的名字要指定准确

   将Dog用Component注解自动生成的bean(dog)注入到DogService之中的dog字段中            

@Component
public class Dog {}
@Service(value = "DogService")
public class DogService {

    private Dog dog;
    @Autowired
    public DogService(Dog dog) {
        this.dog = dog;
    }

    public DogService() {
        System.out.println("调用DogService无参构造函数");
    }
}

(2)@Qualifier - 根据属性名进行注入

Qualifier是和Autowire搭配使用的。

如果使用Autowire类型注入,当一个接口有多个实现类的时候Spring就不知道使用哪个实现类进行注入了。所以此时可以使用@Qualifier("")指定实现类的名称(前提是该实现类要先用注解赋予名称:如@Service(value = "dog1") 

(3)@Resource​​​​​​​ - 根据类型名注入,可以根据名称注入

@Resource:即可以根据类型注入,也可以根据名称注入。
Resource注解用法和前面两种一样,在引用数据的上面加上@ Resource,如果是根据属性类型注入,直接@Resource,若是根据属性名注入,形如@Resource(name=“名称”)

​​​​​​​

(4)@Value - 注入普通类型属性

@Value:注入普通数据类型。
这个注入方法就是注入普通数据类型的,比如int,String,Boolean等都是普通数据类型。使用的时候只需要在属性上面加上
@Value(“值”)就可以了

IOC操作Bean管理(完全注解开发)

​​​​​​​使用类代替xml

@Configuration
@ComponentScan(basePackages = {"service"})
public class SpringConfig {
}
    @Test
    public void testAutowireAll(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
        DogService dogService = applicationContext.getBean("DogService", DogService.class);
        System.out.println(dogService);
    }


AOP 

场景引入:

问题提出:

针对带日志功能的实现类,我们发现有如下缺陷

对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力

附加功能分散在各个业务功能方法中,不利于统一维护

解决思路:

解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。

困难:

要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。

所以需要引入新的技术

AOP(概念)

(1)AOP全称面向切面编程,利用AOP可以降低耦合度,提高开发效率

(2)通过不修改源代码的方式,在主干里面添加新功能

AOP(底层原理) 

1、AOP底层使用动态代理

(1)有接口的情况,使用JDK动态代理

                - 该接口实现类的代理对象

(2)无接口的情况,使用CGLIB动态代理

                - 该类子类的代理对象

AOP(作用) 

1、简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。

2、代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了。

AOP(动态代理) 

生产代理对象的工厂类:

 测试:

传一个实现接口类到工厂,工厂进行逻辑写入后传出,实现解耦

AOP概念及相关术语

1、横切关注点

从每个方法中抽取出来的同一类非核心业务。在同一个项目中,我们可以使用多个横切关注点对相关方法进行多个不同方面的增强。

这个概念不是语法层面天然存在的,而是根据附加功能的逻辑上的需要:有十个附加功能,就有十个横切关注点。

2、通知

每一个横切关注点上要做的事情都需要写一个方法来实现,这样的方法就叫通知方法。

· 前置通知:在被代理的目标方法前执行

· 返回通知:在被代理的目标方法成功结束后执行(寿终正寝)

· 异常通知:在被代理的目标方法异常结束后执行(死于非命)

· 后置通知:在被代理的目标方法最终结束后执行(盖棺定论)

· 环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对· 应的所有位置

3、切面

封装通知的类

4、目标

被代理的目标对象

5、代理

向目标对象应用通知之后创建的代理对象。

6、连接点

向目标对象应用通知之后创建的代理对象。

7、切入点

定位连接点的方式。

每个类的方法中都包含多个连接点,所以连接点是类中客观存在的事物(从逻辑上说)。

如果把连接点看作数据库中的记录,那么切入点就是查询记录的 SQL 语句。Spring 的 AOP 技术可以通过切入点定位到特定的连接点。切点通过 org.springframework.aop.Pointcut 接口进行描述,它使用类和方法作为连接点的查询条件。

基于注解的AOP

 (2)cglib就是实例化子类

 通过Maven仓库导入相关依赖

文件结构:

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com</groupId>
    <artifactId>GarsonSpring</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <spring.version>5.2.2.RELEASE</spring.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>9</source>
                    <target>9</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <name>GarsonSpring</name>

    <dependencies>
<!--测试需要的依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>compile</scope>
        </dependency>
<!--SpringAOP-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2</version>
        </dependency>

    </dependencies>

</project>

Spring.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.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy />
    <!--开启注解扫描-->
    <context:component-scan base-package="SpringAOP.aop" />
</beans>

User:

package SpringAOP.aop;

import org.springframework.stereotype.Component;

@Component
public class User {
    public void add(){
        System.out.println("add...");
    }
}

UserProxy:

package SpringAOP.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy {

    //前置通知
    @Before("execution(* SpringAOP.aop.*.*(..))")
    public void before(){
        System.out.println("before");
    }

}

AOP(开始操作)

成功完成本模块中的<实际操作>就代表可以正确运行AOP

1、 切入点表达式:

(1)知道对哪个类里面的哪个方法进行增强

(2)语法结构:

        此表达式表示对SpringAOP.aop包中的所有类的所有方法进行增强

          @Pointcut("execution(* SpringAOP.aop.*.*(..))")

        此表达式表示对SpringAOP.aop包中User类的add方法进行增强

          @Pointcut("execution(* SpringAOP.aop.User.add(..))")

2、进行通知的配置

(1) 在spring配置文件中,开启注解扫描

            ·在“通过Maven仓库导入相关依赖”中就已设置

(2)使用注解创建User和UserProxy对象

           ·即在类前面增加@Component

           ·使得可以使用xml中的注解创建对象

(3)在增强类(UserProxy)上面添加注解@Aspect

           ·如果有AspectJ就生成代理对象

(4)在Spring配置文件中开启生成代理对象

           ·在“通过Maven仓库导入相关依赖”中就已设置

<实际操作(代码复制可直接运行)>

类:

package SpringAOP.aop;

import org.springframework.stereotype.Component;

@Component
public class User {
    public void add(){
        System.out.println("add...");
    }
}

增强类:

package SpringAOP.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

//增强的类
@Component
@Aspect//生成代理对象
public class UserProxy {

    //前置通知
    @Before("execution(* SpringAOP.aop.*.*(..))")
    public void before(){
        System.out.println("before");
    }

}

测试方法:

    @Test
    public void test1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        User user = applicationContext.getBean("user", User.class);
        user.add();
    }

测试结果:

总结:

AOP其实就是在一个固定的类外面套一层代理类,在代理类可以增加你希望的方法及操作但却不需要改变原始类。达到了解耦合的目的,更利于维护。

 AOP术语

在结束上面的AOP引入,相信我们已经对AOP有一些了解了

接下来我们再了解更深入一点的AOP术语

 AOP五种通知

上文我们使用到了@Before。有了在指定方法前执行,

那就肯定有在后面、在异常抛出后、前后都执行...等,下面我们将介绍AOP的五种通知

@Before, 在 join point 前被执行的 advice. 虽然@Before是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常。

@AfterReturning, 在一个 join point 正常返回后执行的 advice

@AfterThrowing, 当一个 join point 抛出异常后执行的 advice
@After( = final), 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice
@Around, 在 join point 前和 joint point 退出后都执行

AOP相同切入点的抽取

(很多人这一点讲的很复杂)

我用流程来说明:其实@Before的对象现在是pointCutDemo()方法了,但是pointCutDemo指向的是SpringAOP.aop.User类中的add()方法。所以Before还是会在add()方法之前执行

一句话:before() 在 pointCutDemo = User.add() 方法前执行

    @Pointcut("execution(* SpringAOP.aop.User.add(..))")
    public void pointCutDemo(){}


    //前置通知
    @Before("pointCutDemo()")
    public void before(){
        System.out.println("before");
    }

有多个增强类对同一个同一个方法进行增强

设置增强类优先级

就是有很多男生约一个女生吃饭,那女生就要给男生们排序号啦

有多个代理类想代理,我们给代理类设置一个优先级

在增强类上面添加注解@Order(数字类型值),数字类型值越小等级越高

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值