一、Spring简介

1、优点

  • Spring是 一个开源的免费的框架(容器)
  • Spring是一个轻量级的、非入侵式的框架
  • 控制反转(IoC Inversion of Control) 面向切面编程(AOP )
  • 支持事务的处理,对框架整合的支持!

2、主要作用:

​ Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。就是让对象和对象(模 块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在 Spring 中说明对象(模 块)的关系。 Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度。 IoC 使得主业务在相互 调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring 容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且 不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成 “织入”。

​ Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

3、spring7大组件

image-20210721124750969

二、IoC

工厂模式、反射、xml解析

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了.

图片

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

图片

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

一、Hello Spring开发步骤

image-20210721143738422

image-20210721143815004

1、导入Spring开发的基本依赖
2、编写Dao接口和实现类
3、创建spring核心配置文件
4、在spring配置文件中配置UserDaoImpl
5使用Spring API获得Bean实例

1、导入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.6</version>
</dependency>
   
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.6</version>
</dependency>

    

2、编写一个Hello实体类

public class Hello {
   private String name;

   public String getName() {
       return name;
  }
   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("Hello,"+ name );
  }
}

3、配置beans.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就是java对象 , 由Spring创建和管理-->
   <bean id="hello" class="com.kuang.pojo.Hello">
       <property name="name" value="Spring"/>
   </bean>

</beans>

4、进行测试

@Test
public void test(){
   //解析beans.xml文件 , 生成管理相应的Bean对象
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //getBean : 参数即为spring配置文件中bean的id .
   Hello hello = (Hello) context.getBean("hello");
   hello.show();
}
  • Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的】
  • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

//beans架子

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

</beans>

二、IoC创建对象

1.使用无参创建 默认 set 方式注入

2.使用有参创建

2.1下标赋值
 <bean id="user" class="com.cx.pojo.User">
        <constructor-arg index="0" value="aaaaa陈鑫"/>
 </bean>
2.2类型赋值
<bean id="user" class="com.cx.pojo.User">
       <constructor-arg type="java.lang.String" value="cx"/>
   </bean>
2.3直接通过参数名来设置
 <bean id="user" class="com.cx.pojo.User">
        <constructor-arg name="name" value="陈鑫第三种方式"/>
    </bean>

在配置文件被加载的时候,容器中管理的对象就已经开始初始化

三、Spring配置

1、别名

<!-- 别名,也可以使用别名获取对象-->
    <alias name="user" alias="111sddddd"/>

2、Bean的配置

<!--id:唯一标识符,相当于对象的对象名
    class: bean对象所对应的全限定名  包名 + 类型
    name:别名-->
    <bean id="UserT" class="com.cx.pojo.UserT" name="user2 u2,u3;u4" >
        <property name="name" value="科城"/>
    </bean>

3、import

一般用于团队配置,可以将多个配置文件导入合并为一个

项目有多个人开发,复制不同的类,在不同的bean中配置注册,可以利用import将所有人的bean.xml合并为一个总的applicationContent.xml


    <import resource="beans2.xml"/>
    <import resource="beans.xml"/>
 

使用的时候直接使用总的配置就行了

四、DI(依赖注入)

1、构造器注入

2、setter注入【重点】

  • 依赖注入 :set注入

    依赖:bean对象中的创建依赖于容器中

    注入: bean对象中的所有属性,由容器创建

    【环境搭建】

    1.复杂类型

    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    

    2.真实测试对象

    
    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private Map<String,String> card;
        private List<String> hobbys;
        private Set<String> games;
        private String wife;
        private Properties info;
    get set toString方法
    
    

    3.beans.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">
       beans/>
    

    4.完善注入信息

     <bean id="address" class="com.cx.pojo.Address">
            <property name="address" value="成都"/>
        </bean>
    
        <bean id="student" class="com.cx.pojo.Student">
            <!--第一种 普通值注入 value-->
            <property name="name" value="陈鑫"/>
    
            <!--第二种 Bean注入 ref-->
            <property name="address" ref="address"/>
    
            <!--第3种 数组注入-->
            <property name="books">
                <array>
                    <value>三国演义</value>
                    <value>红楼梦</value>
                    <value>水浒传</value>
                </array>
            </property>
    
            <!--第4种 map注入-->
            <property name="card">
                <map>
                    <entry key="身份证" value="1234567890"/>
                    <entry key="银行卡" value="1111111111"/>
                </map>
            </property>
    
            <!--第5种 list注入-->
            <property name="hobbys">
                <list>
                    <value>敲代码</value>
                    <value>看书</value>
                    <value>打游戏</value>
                </list>
            </property>
    
            <!--第6种 set注入-->
            <property name="games">
                <set>
                    <value>LOL</value>
                    <value>王者</value>
                    <value>吃鸡</value>
                </set>
            </property>
    
            <!--第7种 null注入-->
            <property name="wife">
               <null/>
            </property>
    
            <!--第8种 Properties注入-->
            <property name="info">
                <props>
                    <prop key="driver">11</prop>
                    <prop key="url">localhost:3306</prop>
                    <prop key="username">root</prop>
                    <prop key="passwords">123456</prop>
                </props>
            </property>
    
        </bean>
    
    

    5.test

    public class Mytest {
        public static void main(String[] args) {
           ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            Student student = (Student) context.getBean("student");
            System.out.println(student.toString());
    

    6.输出

    Student{
    //        name='陈鑫',
    //        address=Address{address='成都'},
    //        books=[三国演义, 红楼梦, 水浒传],
    //        card={
    //        身份证=1234567890,
    //        银行卡=1111111111},
    //        hobbys=[敲代码, 看书, 打游戏],
    //        games=[LOL, 王者, 吃鸡],
    //        wife='null',
    //        info={
    //        url=localhost:3306,
    //        driver=11,
    //        passwords=123456,
    //        username=root}
    }
    

    3、接口注入

    侵入行太强,不建议使用

    4、拓展注入

我们可以使用p命名和c命名空间进行注入

官方介绍:

image-20210529145119972

p命名

<bean id="user" class="com.cx.pojo.User" p:name="cx" p:age="11"/>

p命名

    <bean id="user2" class="com.cx.pojo.User" c:age="18" c:name="cx c注入"/>

测试

  @Test
    public void test2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user2", User.class);
        System.out.println(user);

注意点:使用p命名和p命名需要导入约束

 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:c="http://www.springframework.org/schema/c"

五、Bean Scopes

Bean 作用域

image-20210529141146294

1.单例模式(Singleton)

Spring默认模式

image-20210529145528368

<bean id="user2" class="com.cx.pojo.User" c:age="18" c:name="cx c注入" scope="singleton"/>

测试

image-20210529150044955

2.原型模式(Prototype)

每从容器中get的时候,都会产生新的对象

image-20210529145549124

<bean id="user2" class="com.cx.pojo.User" c:age="18" c:name="cx c注入" scope="prototype"/>

测试

image-20210529150219099

3.其余的request,session,application这些只能在web中开发才能用到

六、Bean的自动装配

  • 自动装配是spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

Spring自动装配的三种方式

1、在xml中实现配置

ByName自动装配
 <bean id="cat" class="com.cx.pojo.Cat"/>
    <bean id="dog11" class="com.cx.pojo.Dog"/>

<!--byName  自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id-->
    <bean id="people" class="com.cx.pojo.People" autowire="byName">
      <property name="name" value="陈鑫miao~"/>
      <property name="cat" ref=""/>
      <property name="dog" ref="dog"/>
    </bean>

ByType自动装配
    <bean id="cat" class="com.cx.pojo.Cat"/>
    <bean id="dog11" class="com.cx.pojo.Dog"/>
	<!--byType 没有id也能run-->
	<!--<bean  class="com.cx.pojo.Cat"/>-->
	<!--<bean class="com.cx.pojo.Dog"/>-->
	<!--byType 自动在容器上下文中查找和自己对象属性相同的bean-->

    <bean id="people" class="com.cx.pojo.People" autowire="byType">
        <property name="name" value="陈鑫miao~"/>
	<!--<property name="cat" ref="猫"/>-->
	<!--<property name="dog" ref="dog"/>-->
    </bean>

小结:

  • 使用byname的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致!
  • 使用bytype的时候,需要保证所有的bean的Class唯一,并且这个bean需要和自动注入的属性的类型一致!

2、在java中显示配置,注解方式

使用注解实现自动装配

使用注解须知

  • 导入约束 context约束

    <context:annotation-config/>
    
  • 配置注解的支持

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

@Autowired 直接在属性(字段)上使用!也可以在set上使用!

如果找不到,就用@Qualifier配套使用 ,可以无需set方法

public class People {
    @Autowired
    @Qualifier(value = "cat11")
    private Cat cat;

    @Autowired
    @Qualifier(value="dog11")
    private Dog dog;
    private String name;

@Nullable 字段标记了就可以为空

public @interface Autowired {
    boolean required() default true;
}

@AutoWried按bytype自动注入

@Resource默认按byName自动注入,如果找不到名字,则通过byType实现!如果两种都没有找到的情况,就报错!

3、隐式的自动装配bean【重要】

三、AOP

spring AOP(Aspect-oriented programming) 是用于切面编程,简单的来说:AOP相当于一个拦截器,去拦截一些处理,例如:当一个方法执行的时候,Spring 能够拦截正在执行的方法,在方法执行的前或者后增加额外的功能和处理。

一、代理模式

为什么要学习AOP,这是SpringAOP的底层 【SpringAOP和SpringMVC】

二、代理模式分类:

1、静态代理

角色分析:

  • 抽象角色:一般使用接口或者抽象类解决
  • 真实角色:被代理的角色
  • 代理角色:代理真理角色。代理真实角色后,我们一般会做一些复数操作
  • 客户:被访问代理对象的人

代码步骤:

1.接口

public interface UserService {
    
    //4个连接点
    public void add();
    public void delete();
    public void update();
    public void querry();
}

2.真实角色

public class UserServiceImpl implements UserService{
//具体实现方法  切入点
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");

    }

    @Override
    public void update() {
        System.out.println("修改了一个用户");

    }

    @Override
    public void querry() {
        System.out.println("查询了一个用户");

    }
}

3.代理角色

public class UserServiceProxy implements UserService{

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    private UserService userService;
    @Override
    public void add() {
        log("add");
        userService.add();
    }

4.客户端代理角色

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);

        proxy.delete();


    }

2、动态代理(核心:反射)

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 ----JDK动态代理 通过接口 有接口时使用
    • 基于类-----CGLIB 通过子类增强逻辑 没有接口时使用
    • 基于java字节码:JAVAsist

两个类:Proxy 代理对象, Innovationhandler 调用程序实现的接口

代码实现:

1.创建方法接口


public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}

2.创建实现类

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

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

3.使用proxy类创建接口代理对象

调用newProxyInstance方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7F6QtmjZ-1626853751242)(Spring.assets/image-20210704133150378.png)]

该方法有三个参数:

  1. 类加载器
  2. 增强方法所在类,这个类实现的接口,支持多个接口
  3. 实现这个接口InvocationHandler,创建代理对象,写增强的方法
public class JDKProxy {
    public static void main(String[] args) {
        //创建实现代理类代理对象
        Class[] interfaces = {UserDao.class};
//       方法一:匿名内部类  new InvocationHandler()
//       Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                return null;
//            }
//        });
        UserDaoImpl userDao = new UserDaoImpl();
        UserDao dao= (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int res = dao.add(1, 4);
        System.out.println("result="+res);
    }
}
//方法二:创建代理对象代码
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;
    }
}

4.测试

image-20210704140757369

三、AOP(术语)

  1. 连接点

    可以被增强的方法,这些方法被称为连接点

  2. 切入点

    实际被真正增强的方法,被称为切入点

  3. 通知(增强)

    实际增强的逻辑部分

  • 前置通知 方法之前
  • 后置通知 方法之后
  • 环绕通知 方法之前、方法之后都执行
  • 异常通知 方法出现了异常执行
  • 最终通知 finally 不管,都执行

4.切面(动作)(Aspect)

把通知应用到切入点过程 (登录过程中加入判断)

四、AOP操作

Spring一般使用AspectJ实现AOP操作

AspectJ实际上是对AOP编程思想的一个实践,当然,除了AspectJ以外,还有很多其它的AOP实现,例如ASMDex,但目前最好、最方便的,依然是AspectJ。

依赖:

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.6</version>
    </dependency>

基于AspectJ实现操作

1.基于xml配置文件实现

2.基于注解方式实现

4.1、切入点表达式

4.1.1、作用:

知道对哪个类里的方法进行增强

4.1.2、语法结构:
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
    
举例1:对com.cx.dao.BookDao类的add方法进行增强
    execution(* com.cx.dao.BookDao.add(..))
    *表示任意修饰符
    [返回类型] 可以省略
    ..  参数列表
    
 举例2:对com.cx.dao.BookDao类的所有方法进行增强
     execution(* com.cx.dao.BookDao.*(..))
    
 举例3:对com.cx.dao包里面的所有类,所有方法进行增强
    execution(* com.cx.dao.*.*(..))
    

五、基于AspectJ实现操作

1.基于xml配置文件实现

  1. 创建两个类,增强类和被增强类,创建方法
public class Book {
    public void buy(){
        System.out.println("buy .........");
    }
}

public class BookProxy {
    public void before(){
        System.out.println("before.........");
    }
}


2.在spring配置文件中创建两个对象

<?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">
<!--创建对象-->
    <bean id="book" class="com.cx.aopxml.Book"></bean>
    <bean id="bookProxy" class="com.cx.aopxml.BookProxy"></bean>
</beans>

3.在spring配置文件在中配置切入点

配置aop增强
<aop: config>

  <!-- 配置aop增强-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="p" expression="execution(* com.cx.aopxml.Book.buy(..))"/>
        <!-- 配置切面-->
        <aop:aspect ref="bookProxy">
        <!-- 增强在具体的方法上-->
            <aop:before method="before" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>


4、测试

  @Test
    public void testAopXml(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        Book book = (Book) context.getBean("book");
        book.buy();
    }

5、运行

image-20210705115525530

2.基于AspectJ注解方式实现

  1. 创建类,在类里面定义方法

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

2.创建增强类,在里面创建方法,让不同方法代表不同通知类型

//增强的类
public class UserProxy {
    
    //前置通知
    public void before(){
        System.out.println("before.....");
    }
}

3.进行通知的配置

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

 <context:component-scan base-package="com.cx.aopanno"></context:component-scan>
<?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="com.cx.aopanno" ></context:component-scan>

</beans>

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

@Component

//被增强的类
@Component
public class User {
    public void add(){
        System.out.println("add......");
    }
}

@Component
//增强的类
public class UserProxy {
    //前置通知
    public void before(){
        System.out.println("before.....");
    }
}

3、在增强类上面添加注解@Aspect


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

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

4、在spring配置文件中开启生成代理对象

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

5、配置不同类型的通知

ps:在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

@Before(value = “execution(* com.cx.aopanno.User.add(…))”)

@Component
@Aspect
//增强的类
public class UserProxy {
    //前置通知
    @Before(value = "execution(* com.cx.aopanno.User.add(..))")
    public void before(){
        System.out.println("before.....");
    }
}

6、测试

public class MyTest {
    @Test
    public void testAopAnno(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        User user = (User) context.getBean("user");
        user.add();
    }
}

7、结果

image-20210704211706915

8、其他通知

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

    //前置通知
    @Before(value = "execution(* com.cx.aopanno.User.add(..))")
    public void before(){
        System.out.println("before.....");
    }
    
    //无论什么情况下都会执行的方法
    @After(value = "execution(* com.cx.aopanno.User.add(..))")
    public void after(){
        System.out.println("after.....");
    }
    
    //方法返回值之后执行
    @AfterReturning(value = "execution(* com.cx.aopanno.User.add(..))")
    public void afterReturning(){
        System.out.println("afterReturning.....");
    }
	//异常
    @AfterThrowing(value = "execution(* com.cx.aopanno.User.add(..))")
    public void afterThrowing(){
        System.out.println("afterThrowing.....");
    }

	//环绕
    @Around(value = "execution(* com.cx.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("around之前.....");
        proceedingJoinPoint.proceed();
        System.out.println("around之后.....");
    }
}

六、切入点抽取

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

    }

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

七、设置增强类优先级

有多个增强类同一个方法进行增强,设置增强类优先级

@Order 数字越小,优先级越高

@Component
@Aspect
@Order(1)
public class PersonProxy {
    @Before(value = "execution(* com.cx.aopanno.User.add(..))")
    public void before(){
        System.out.println("person before.....");
    }

}

八、执行顺序

try{
    try{
        //@Before
        method.invoke(..);
    }finally{
        //@After
    }
    //@AfterReturning
}catch(){
    //@AfterThrowing
}

九、完全使用注解方式实现

//完全注解
@Configuration
@ComponentScan(basePackages = {"com.cx"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class config {
    
}

四、事务

这两条SQL语句必须全部执行,或者,由于某些原因,如果第一条语句成功,第二条语句失败,就必须全部撤销。

这种把多条语句作为一个整体进行操作的功能,被称为数据库事务

数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败,那么效果就和没有执行这些SQL一样,不会对数据库数据有任何改动。

经典场景:银行转账

可见,数据库事务具有ACID这4个特性:

  • A:Atomic,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;
  • C:Consistency,一致性,事务完成后,所有数据的状态都是一致的,即A账户只要减去了100,B账户则必定加上了100;
  • I:Isolation,隔离性,如果有多个事务并发执行,每个事务作出的修改必须与其他事务隔离;
  • D:Duration,持久性,即事务完成后,对数据库数据的修改被持久化存储。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐