Spring详细学习-IOC和AOP学习

Spring详细学习

Spring框架概念&目的&特点

概念:轻量级开源的JAVAEE框架

目的:简化企业开发而存在的框架

特点:
(1)方便解耦,简化开发

(2)AOP编程支持

(3)方便程序测试

(4)方便和其他框架整合入mybatis

(5)方便对事物的操作

(6)降低API的开发难度

IOC容器

IOC(控制翻转)

概念:把创建过程交给spring进行管理

IOC概念及底层原理:

: 什么是IOC?
把对象的创建和对象之间引用的过程都交给Spring进行管理,目的是耦合性降低

: IOC的底层原理:
xml解析、工厂设计模式、反射
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

IOC接口(Beanfactory)

IOC的思想基于IOC容器完成,IOC底层就是对象的工厂
Spring提供IOC容器实现方式:(两个接口)
1、BeanFactory
是IOC中最基本的实现方式,是spring内部使用的接口,不提供开发人员使用
特点:加载配置文件是不会创建对象,在获取或使用对象时才会创建对象
2、ApplicationContext
是BeanFactory的子接口,功能强大,面向开发人员
特点:在加载配置文件时,就会把配置文件对象进行创建
平常使用这种方式是把创建对象这个过程交给服务器完成,就不会在操作时完成。
3、ApplicationContext接口的实现类
CtrlH打开类结构
在这里插入图片描述
FileSystemXmlApplicationContext是盘的路径
ClassPathXmlApplicationContext是类路径

IOC操作 Bean管理(创建对象&注入属性)

: 什么是Bean管理,两个操作:
1、由spring创建对象
2、spring注入属性

IOC操作Bean管理(基于xml配置文件)
1)基础XML方式创建对象
在这里插入图片描述
1.在xml文件中使用bean标签,标签里加上对应的属性,就可以实现对象的创建
2.bean下很多属性,常见属性如下:
id属性:唯一标识
class属性:类全路径(包类路径)
name属性:和id属性一样,还可加特殊符号,id中不可,都用id属性
3.默认情况是执行无参数的构造方法,完成对象的创建

2)基础XML方式注入属性

DI:依赖注入,就是注入属性,DI是IOC中一种具体实现

第一种方式使用setter方法进行注入
第一步:创建属性、创建set方法
在这里插入图片描述
第二步:在Spring配置文件配置对象创建,配置属性注入
在这里插入图片描述

Set方法简化写法:(了解)
P名称空间注入,简化XML配置方式
第一步:XML中增加P约束:在这里插入图片描述
第二步:在bean标签中进行操作
在这里插入图片描述

第二种注入方式通过有参数的构造注入
第一步:创建类定义属性,然后创建带属性的构造方法
第二步:在spring配置文件中进行配置
在这里插入图片描述
其中constructor-arg中有index属性是按参数的索引比如index=0,取第一个,用确定值比较好。

IOC操作Bean管理(基于xml配置文件,注入其他类型属性)

字面量

1)null值:在property中加入null标签

 设置null值
        <property name="address">
        <null/>
        </property>

2)特殊符号

 <!--属性值中包含特殊符号
        1.<>进行转译&lt &gt
        2.把带特殊符号的内容写到CDATA
        -->
        <property name="address">
            <value><![CDATA[<<测试>>]]>

            </value>
        </property>
注入属性-外部bean

(1)创建2个类service类和dao类
(2)在service调用dao里面的方法
(3)在spring配置文件中配置

//创建UserDao属性,生成对应的setter方法
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }


<!-- 1.serive和dao的对象创建/-->
    <bean id="userService" class="service.UserService">
        <!--注入userDao对象
        name属性:类里面的属性名称
        ref属性:创建userDao对象bean标签id值
        -->
        <property name="userDao" ref="userDaoIm"></property>
    </bean>
    <bean id="userDaoIm" class="com.spring5.dao.UserDaoIm"></bean>

注意这里是在xml配置文件中放了接口的实现方法类,这就是多态。

注入属性-内部Bean

(1)一对多关系,部门和员工
(2)在实体类中表示1对多的关系,员工表示所属部门,使用对象类型属性表示

    //部门类
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }
    
   //员工类
    private String ename;
    private String gender;
    private Dpmt dpmt;
    public void setDpmt(Dpmt dpmt) {
        this.dpmt = dpmt;
    }

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

    <!--内部bean-->
    <bean id="emp" class="com.spring5.bean.Emp">
        <!--先设置2个普通属性-->
        <property name="ename" value="惠桢"></property>
        <property name="gender" value="女"></property>
        <!--设置对象属性
        1.可以用外部bean的ref代替value去写
        2.property中嵌套对象
        -->
        <property name="dpmt">
            <bean id="Dpmt" class="com.spring5.bean.Dpmt">
                <property name="dname" value="数据中心"></property>
            </bean>
        </property>
    </bean>
注入属性-级联赋值

(1)第一种写法

 <!--级联赋值-->
    <bean id="emp" class="com.spring5.bean.Emp">
        <!--先设置2个普通属性-->
        <property name="ename" value="惠桢"></property>
        <property name="gender" value="女"></property>
        <!--级联赋值-->
        <property name="dpmt" ref="dpmt"></property>
    </bean>
    <bean id="dpmt" class="com.spring5.bean.Dpmt">
        <property name="dname" value=""></property>
    </bean>

(2)第二种写法(需要生成对应的get方法,才能设置)

 <!--级联赋值-->
    <bean id="emp" class="com.spring5.bean.Emp">
        <!--先设置2个普通属性-->
        <property name="ename" value="惠桢"></property>
        <property name="gender" value="女"></property>
        <!--级联赋值-->
        <property name="dpmt" ref="dpmt"></property>
        <property name="dpmt.dname" value="技术部"></property>

    </bean>
    <bean id="dpmt" class="com.spring5.bean.Dpmt">
        <property name="dname" value=""></property>
    </bean>

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

1、注入数组类型属性
2、注入List集合属性
3、注入Map集合属性
4、注入Set集合属性
(1)创建类,定义数组类型、LIst、Map、Set生成对应的set方法。

    //1.数组类型属性
    private String[] courses;
    //2.创建集合list类型属性
    private List<String>  list;
    //3.创建map集合属性
    private Map<String,String> maps;
    //4.set集合类型属性
    private Set<String> sets;
	//学生所学多门课程
    private List<Course>  courseList;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

(2)xml配置文件配置

    <!--1.集合类型属性的注入-->
    <bean id="stu" class="com.spring5.collectiontype.Stu">
        <!--数组类型的属性注入
        用array标签或list标签都可以
        -->
        <property name="courses">
            <array>
                <value>JAVA课程</value>
                <value>Mysql课程</value>
            </array>
        </property>
        <!--list类型属性注入-->
        <property name="list">
            <array>
                <value>张三</value>
                <value>小三</value>
            </array>
        </property>
        <!--Map类型属性注入-->
        <property name="maps">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="MYSQL" value="mysql"></entry>
            </map>
        </property>
        <!--Set类型属性注入-->
        <property name="sets">
            <set>
                <value>Mysql</value>
                <value>Redis</value>
            </set>
        </property>
        <!--注入list集合类型,值是个对象的形式-->
        <property name="courseList">
            <list>
                <ref bean="couser1"></ref>
                <ref bean="couser2"></ref>
            </list>
        </property>
    </bean>
    <bean id="couser1" class="com.spring5.collectiontype.Course">
        <property name="cname" value="Spring5框架课程"></property>
    </bean>
    <bean id="couser2" class="com.spring5.collectiontype.Course">
        <property name="cname" value="Mybatis框架课程"></property>
    </bean>

注意:
1)如果集合里是对象
设置属性:

  //学生所学多门课程
    private List<Course>  courseList;
        public void setCourses(String[] courses) {
        this.courses = courses;
    }

XML文件中配置:

<property name="courseList">
            <list>
                <ref bean="couser1"></ref>
                <ref bean="couser2"></ref>
            </list>
        </property>
    </bean>
    <bean id="couser1" class="com.spring5.collectiontype.Course">
        <property name="cname" value="Spring5框架课程"></property>
    </bean>
    <bean id="couser2" class="com.spring5.collectiontype.Course">
        <property name="cname" value="Mybatis框架课程"></property>
    </bean>

2)如何把公共部分提取出来
在spring配置文件中引用命名空间:

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

使用标签提取:

    <!--提取list集合类型属性注入-->
    <util:list id="bookList">
        <value>样图灵</value>
        <value>战术</value>
    </util:list>
    <!--提取list集合类型属性注入-->
    <bean id="book" class="com.spring5.collectiontype.Book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>

IOC操作Bean管理(FactoryBean)

Spring有两种类型的Bean,一种为普通bean,一种为工厂bean(FactoryBean)

普通Bean:
在配置文件中定义bean的类型就是返回类型

工厂Bean:(了解)
在配置文件中定义bean类型可以喝返回类型不一致

第一步:创建类作为工厂bean,实现接口FactoryBean
第二部:实现接口里面的方法,在实现方法中定义返回的bean类型

public class  MyBean implements FactoryBean<Course> {

    //定义返回bean对象
    @Override
    public Course getObject() throws Exception {
        Course course=new Course();
        course.setCname("测试");
        return course;
    }

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

    @Override
    public boolean isSingleton() {
        return false;
    }
}

定义了Mybean,返回的是Course

 <bean id="mybean" class="com.spring5.factorybean.MyBean"></bean>

测试类

    @Test
    public void testmybean()
    {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean4.xml");
        Course course =context.getBean("mybean", Course.class);
        System.out.println(course);
    }

IOC操作Bean管理(作用域)

1、在spring里,设置bean的实例是单实例还是多实例
2、在Spring里,默认情况下创建的是单实例对象

    @Test
    public void testBook()
    {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean3.xml");
        Book book1 =context.getBean("book", Book.class);
        Book book2 =context.getBean("book", Book.class);
        Book book3 =context.getBean("book", Book.class);
        System.out.println(book1);
        System.out.println(book2);
        System.out.println(book3);
    }

以上返回的值是同一个地址

3、设置单实例或多实例方法
(1)scope属性值
第一个默认值为singleton,表示单实例
第二个值为prototype

    <!--提取list集合类型属性注入-->
    <util:list id="bookList">
        <value>样图灵</value>
        <value>战术</value>
    </util:list>
    <!--提取list集合类型属性注入-->
    <bean id="book" class="com.spring5.collectiontype.Book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>

4、singleton和prototype的区别
singleton:单实例,加载spring配置文件时就会创建单实例对象
prototype:多实例,不是在加载spring配置时创建对象,当用getBean获取对象时会创建多实例对象。

5、其他值Request和Session
Request:一次请求,会把对象放Request中
Session:一次会话,会把对象放Session中

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

生命周期

概念:从对象创建到销毁的过程

bean的生命周期流程

(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和其他bean的引用(调用set方法)
(3)调用bean的初始化的方法(需要配置)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时,调用bean的销毁的方法(需要配置)

bean的生命周期的演示
    //无参数构造

    public Orders()
    {
        System.out.println("第一步执行无参构造创造bean实例");
    }


    private String oname;

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步调用set方法设置属性值");
    }

    //创建执行初始化的方法

    public void initMethod()
    {
        System.out.println("第三步:执行初始化的方法");
    }

    //创建销毁执行的方法
    public void destroyMethod()
    {
        System.out.println("第五步:创建销毁");
    }
    <!--3.通过init-method调用初始化方法
        4.通过destroymethod调用摧毁方法-->
    <bean id="orders" class="com.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod">
        <property name="oname" value="产品"></property>
    </bean>
    @Test
    public void testBean5()
    {
//        ApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
//这里通过修改ApplicationContext为子类接口可执行close方法,否则用子类要强转
        ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean5.xml");
        Orders orders =context.getBean("orders", Orders.class);
        //4.第四步:获取创建bean的实例对象
        System.out.println(orders);
        //手动让bean实例销毁
        context.close();
    }

测试演示:
在这里插入图片描述

bean的后置处理器(bean生命周期有7步)

(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和其他bean的引用(调用set方法)
(3)把bean的实例传给后置处理器的方法
执行方法:postProcessBeforeInitialization
(4)调用bean的初始化的方法(需要配置)
(5)把bean的实例传给后置处理器的方法
执行方法:
(6)bean可以使用了(对象获取到了)
(7)当容器关闭时,调用bean的销毁的方法(需要配置)

bean的后置处理器的演示

(1)创建类,实现接口BeanPostProcessor, 创建后置处理器

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之前执行的方法");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("在初始化之后执行的方法");
        return bean;
    }

}

(2)在配置文件中配置后置处理器

    <!--配置后置处理器(会为所有的bean添加后置处理器)-->
    <bean id="mybeanpost" class="com.spring5.bean.MyBeanPost"></bean>

执行效果:
在这里插入图片描述

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

自动装配(用的少,一般用注解)

根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

演示自动装配过程

(1)根据属性名称自动装配

    <!--实现自动装配
     bean标签属性autowire,配置自动装配
     autowire常用两个值:byName根据属性名称注入 byType根据属性类型注入
     特点:需要注入bean的id值必须和类的属性名称一致
     -->
    <bean id="emp" class="com.spring5.autowire.Emp" autowire="byName">
<!--        <property name="dpmt" ref="dpmt"></property>-->
    </bean>

    <bean id="dpmt" class="com.spring5.autowire.Dpmt"></bean>

(2)根据属性类型自动注入
把autowire改为byType,相同类型的类不能创建多个

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

直接配置数据库信息

(1)配置德鲁伊连接池
(2)引入德鲁伊连接池依赖jar包
在这里插入图片描述

<!--直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/userDb" />
        <property name="username" value="root" />
        <property name="password" value="admin" />
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    </bean>
引入外部属性文件配置数据库连接池

(1)创建外部属性文件,properties格式文件,写数据库信息
在这里插入图片描述
(2)把外部的properties属性文件引入spring配置文件中
第一步:在xml配置文件中引入context命名空间

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

第二步:在spring配置文件使用标签引入外部属性文件

    <!--引入外部的属性文件-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--配置连接池-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="${prop.url}" />
            <property name="username" value="${prop.userName}" />
            <property name="password" value="${prop.password}" />
            <property name="driverClassName" value="${prop.driverClass}" />
        </bean>

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

注解的概念

(1)注解是代码的特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值)
(2)注解可以作用在类上面、方法上面、属性上面
(3)注解的目的:简化XML配置

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

下面的四个注解功能是一样的,都可以用来创建对象
@Component
@Service
@Controller
@Repository

基于注解方式实现对象创建
1.引入依赖(JAR包)

在这里插入图片描述

2.开启组件扫描

目的:告诉spring在哪个类里面要用到注解

    <!--开启组件扫描
    1.如果要扫描多个包,多个包之间使用逗号隔开
    2.扫描上层目录
    -->
    <context:component-scan base-package="com.spring5"></context:component-scan>
3.创建类,在类上面添加创建对象注解
//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
@Component(value = "userService")//相当于bean标签中的id值
public class UserService {

    public void add()
    {
        System.out.println("测试");
    }
}

4.开启组件扫描细节配置
<context:component-scan base-package="com.spring5"></context:component-scan>
    <!--例子1
    use-default-filters="false //表示需要自己配置规则
    context:include-filter //设置哪些内容可以扫描
    type="annotation" //表示根据注解扫描
    expression="org.springframework.stereotype.Controller" //表示只扫描这个包下的Controller注解
    -->

    <context:component-scan base-package="com.spring5" use-default-filters="false">
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!--例子2
    context:include-filter设置哪些内容不被扫描
    expression="org.springframework.stereotype.Controller"表示不扫描带Controller的注解
    -->
    <context:component-scan base-package="com.spring5">
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
基于注解方式实现属性注入
@Autowired

根据属性类型进行自动装配

第一步-创建注解对象
把service和dao的对象创建,在service和dao类添加创建对象注解

第二步-注入
在service中注入dao对象,在service类添加dao类型属性,在属性上面使用注解

@Service(value = "userService")//相当于bean标签中的id值
public class UserService {

    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解
    @Autowired
    private UserDao userDao;

    public void add()
    {
        System.out.println("测试");
        userDao.add();
    }
}
@Qualifier

根据属性的名称进行注入。这个注解要和Autowired注解一起使用 。
当一个接口下多个实现类时要用具体名称才知道是要调用哪个类

    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解
    @Autowired
    //根据名称进行注入
    //对应的接口实现类的value和这个一致
    @Qualifier(value = "userDaoIm1")
    private UserDao userDao;
@Resource

可以根据类型注入,也可以根据名称注入。
Resource是javax扩展包里的,官方建议不用这个

//    @Resource      //根据类型进行注入
    @Resource(name = "userDaoIm1")      //根据名称进行注入
    private UserDao userDao;
@Value

注入普通类型属性

 @Value(value = "abc")
    private String uname;
完全注解开发

(1)创建配置类,替代XML的配置文件


@Configuration //作为配置类
@ComponentScan(basePackages = {"com.spring5"})
public class SpringConfig {


}

(2)编写测试类

    @Test
    public void testService2()
    {
        //加载配置类
        ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService=context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

这种开发在实际操作中用SpringBoot,其实就是对spring进行整理

AOP(面向切面)

不改源代码进行功能增强的功能

AOP概念

1、什么是AOP?
(1)AOP叫面向切面编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发的效率。
(2)不通过修改源代码方式,在主干功能里添加新功能
例子如下:
在这里插入图片描述
如果不需要权限判断就可以删除,不需要修改源代码

AOP底层原理

1、AOP底层使用动态代理
(1)有两种情况的动态代理
第一种:有接口的情况,使用jdk动态代理
在这里插入图片描述
创建接口实现类代理对象,增强类方法

第二种:没有接口情况,使用CGLIB动态代理
在这里插入图片描述
创建子类代理对象,增强类方法

AOP(JDK动态代理)

使用JDK动态代理,使用Proxy类里面的方法创建代理对象
在这里插入图片描述
1、调用newProxyInstance方法
在这里插入图片描述
方法有三个参数:
第一个参数,类加载器
第二个参数,增强方法所在类,这个类实现的接口,支持多个接口
第三个参数,实现接口InvocationHandler,创建代理对象,写增强的方法

2、编写JDK动态代理代码
(1)创建接口、定义方法

public interface UserDao {

    public int add(int a, int b);

    public String update(String id);
}

(2)创建接口实现类,实现方法

public class UserDaoIm implements UserDao {
    @Override
    public int add(int a, int b) {
            return a+b;
    }

    @Override
    public String update(String id) {
        return id;
    }
}

(3)使用Proxy类创建接口代理对象

package com.spring5;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类的代理对象
        Class[] interfaces={UserDao.class};
//        Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                return null;
//            }
//        });
        UserDaoIm userDaoIm =new UserDaoIm();
        UserDao dao=(UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDaoIm));
        int result=dao.add(1,2);
        System.out.println(result);

    }
}
//创建代理对象的代码
class UserDaoProxy implements InvocationHandler{

    //1.把创建谁的代理对象,把那个谁传递过来
    //有参数的构造进行传递
    private Object obj;
    public UserDaoProxy(Object obj)
    {
        this.obj=obj;
    }
    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //方法之前
        System.out.println("在方法之前执行"+method.getName()+":传递的参数"+ Arrays.toString(args));

        //被增强的方法执行
        Object res=method.invoke(obj,args);

        //方法之后
        System.out.println("在方法之后执行"+obj);

        return res  ;
    }
}

AOP术语

1、连接点
2、切入点
3、通知(增强)
4、切面

理解概念图如下:
在这里插入图片描述

AOP操作(准备工作)

1、Spring框架一般基于AspectJ实现AP相关操作
(1)AspectJ是什么?
AspectJ不是Spring组成部分,是独立AOP框架,一般把AspectK和Spring框架一起使用进行AOP相关操作。

2、基于AspectJ实现AOP操作
(1)基于XML配置文件方式
(2)基于注解方式实现(使用)

3、在项目工程中引入AOP相关依赖
在这里插入图片描述
4、切入点表达式
(1)切入点表达作用:知道对哪个类里的哪个方法进行增强
(2)语法结构

execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))

(3)
举例1:对com.atguigu.dao.BookDao里面的add进行增强

execution(*com.atguigu.dao.BookDao.add(..))

举例2::对com.atguigu.dao.BookDao里面的所有方法进行增强

execution(*com.atguigu.dao.BookDao.*(..))

举例3:对com.atguigu.dao包里的所有类,和类的所有方法进行增强

execution(*com.atguigu.dao.*.*(..))

AOP操作(AspectJ注解【开发一般用注解】)

创建类和方法

public class User {

    public void add()
    {
        System.out.println("add...");
    }
}

创建增强类(编写增强逻辑)

(1)在增强类里面创建方法,让不同的方法代表不同的通知

//增强类
public class UserProxy {

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

进行通知的配置

(1)在Spring配置文件中开启注解扫描(也可以用完全注解可自己试下)
先引入context和aop的命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
                           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="com.spring5.aopanno"></context:component-scan>
</beans>

(2)使用注解创建User和UserProxy对象
在这里插入图片描述
在这里插入图片描述

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

//增强类
@Component
@Aspect
public class UserProxy {

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

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

    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

配置不同类型的通知

//增强类
@Component
@Aspect
public class UserProxy {

    //前置通知 注意*后有空格
    @Before(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void before()
    {
        System.out.println("before...");
    }
}

测试类:

   @Test
    public void testAopAnno()
    {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");

        User user=context.getBean("user", User.class);
        user.add();
    }

其他通知类型:

package com.spring5.aopanno;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

//增强类
@Component
@Aspect
public class UserProxy {

    //前置通知
    @Before(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void before()
    {
        System.out.println("before...");
    }


    //后置通知(返回通知)
    @AfterReturning(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void afterReturning()
    {
        System.out.println("afterRetruning...");
    }

    //最终通知,有异常也会通知
    @After(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void after()
    {
        System.out.println("after...");
    }

    //异常通知
    @AfterThrowing(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void afterThrowing()
    {
        System.out.println("afterThrowing...");
    }

    //环绕通知:方法前后执行
    @Around(value = "execution(* com.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("aroundbefore...");
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("aroundafter...");
    }
}

相同的切入点抽取

可以发现以上通知的表达式部分都是重复的 ,优点就是如果要改只需要改这一个地方即可

    //相同切入点抽取
    @Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
        public  void  pointDemo()
        {

        }

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

增强类的优先级

多个增强类,对同一个方法进行增强,设置增强类的优先级
在增强类的上面增加注解@Order(数字类型值),数字类型值越小优先级越高,从0开始,0最小


@Component
@Aspect
@Order(1)
public class PerProxy {
    //相同切入点抽取
    @Pointcut(value = "execution(* com.spring5.aopanno.User.add(..))")
    public  void  pointDemo()
    {

    }

    //前置通知
    @Before(value = "pointDemo()")
    public void before()
    {
        System.out.println("Perbefore...");
    }
}
### 增强类的优先级

完全使用注解开发

创建配置类,不需要创建xml配置文件

@Configuration
@ComponentScan(basePackages = {"com.spring5"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}

上面的类可以代替下面的XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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
                           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="com.spring5.aopanno"></context:component-scan>

    <!--开启Aspect生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

AOP操作(AspectJ配置文件)

创建类和方法

创建两个类,增强类和被增强类,创建方法

配置文件创建对象

Spring配置文件中创建两个类对象

    <!--创建对象-->
    <bean id="book" class="com.spring5.aopxml.Book"></bean>
    <bean id="bookproxy" class="com.spring5.aopxml.BookProxy"></bean>

配置文件配置切入单

Spring配置文件中配置切入点

 <!--配置AOP增强-->
    <aop:config>
    <!--配置切入点-->
        <aop:pointcut id="p" expression="execution(* com.spring5.aopxml.Book.buy(..))"/>

        <!--配置切面-->
        <aop:aspect ref="bookproxy">
            <!--增强在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"></aop:before>

        </aop:aspect>

    </aop:config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值