重学Spring总结

news2024/11/28 21:39:20

在这里插入图片描述

1、Spring框架的诞生

文章目录

  • 1、Spring框架的诞生
    • 1、BeanFactory 快速入门
      • 1.1、BeanFactory完成了loC思想的实现:
        • 1)导入Spring相关的依赖:
        • 2)定义Uservice接口及其UserviceImpl实现类;
        • 3)创建Bean的配置资源文件,文件名最好为:applicationContext.xml(规范),将UserServicelmpl的信息配置到该xml中
        • 4)编写测试代码,创建BeanFactory,加载配置文件,获取UserService实例对象
          • 1、通过工厂对象进行创建:
          • 2、直接从classpatch 路径去寻找配置文件创建资源对象(该方式已废弃了解即可)
      • 1.2、使用BeanFactory通过setter方式去实现以下DI依赖注入:
        • 1)定义UserDao接口及其UserDaolmpl实现类
        • 2)修改UserServicelmpl代码,添加一个setUserDao(UserDao userDao)用于接收注入的对象:
        • 3)修改applicationContext.xml配置文件,定义UserService的<bean>中嵌入<property>配置注入UserDao;
        • 4)修改测试代码,获得UserService时,setUserService方法执行了注入操作。
          • 打个断点:此时userDao,已经被注入
    • 2、ApplicationContext 快速入门(重要)
        • 2.1、ApplicationContext实现Ioc思想
          • 1)前三步和BeanFactry相同
          • 5)读取核心配置文件获取实例化容器对象
    • 3、BeanFactory与ApplicationContext的关系:
    • 4、BeanFactory的继承体系
      • BeanFactory的继承体系
    • 5、ApplicationContext的继承体系
      • 1.ApplicationContext的继承体系
      • 2.只在Spring基础环境下,常用的三个ApplicationContext作用如下:
      • 3.在Spring的web环境下,常用的两个ApplicationContext作用如下
  • 2、基于XML的Spring应用
    • 2.1、SpringBean的配置详解
      • Spring开发中主要是对Bean的配置,Bean的常用配置一览如下:
      • 1)Bean的基础配置
        • 例如:配置UserDaolmpl由Spring容器负责管理
      • 2) Bean的别名配置
        • 可以为当前Bean指定多个别名,根据别名也可以获得Bean对象
      • 3) Bean的范围配置
        • 默认情况下,单纯的Spring环境Bean的作用范围有两个: Singleton和Prototype
      • 4) Bean的延迟加载
      • 5)Bean的初始化和销毁方法配置
        • 扩展: 除此之外,我们还可以通过实现 lnitializingean 接口,完成一些Bean的初始化操作,如下
      • 6)Bean的实例化配置
        • Spring的实例化方式主要如下两种:
        • **构造方式实例化:**
        • **工厂方式实例化:**
          • 1) 、静态工厂方法实例化Bean
          • 2)、实例工厂方法:
          • 3)、Bean的实例化配置:
      • 7)Bean的依赖注入配置
        • Bean的依赖注入有两种方式:
        • 依赖注入的数据类型有如下三种:
        • 一、通过Seet方法进行注入
          • 1)对于list注入:
          • 5)、注入 Set 集合
          • 3)、注入 Map 集合
          • 4)、注入 Properties 键值对
        • 扩展:自动装配方式
    • 2.2、Spring 的getBean方法
    • 2.3、Spring 配置非自定义Bean
      • 列子:
        • 1)配置 Druid 数据源交由Spring管理
  • 3、基于注解诞的Spring应用
    • 1、Bean基本注解开发
    • 2、Bean依赖注入注解开发
      • 1)、@Value
      • 2)、@Autowired注解
      • 3)、@Resource注解
    • 3、非自定义Bean注解开发
        • 如果@Bean工厂方法需要参数的话,则有如下几种注入方式:
    • 4、Bean配置类的注解开发
  • 4、Spring Aop
    • 1、AOP 简介
      • 1.1、AOP的概念
      • 1.2、AOP思想的实现方案
      • 1.3、Aop简介
        • 模拟AOP的基础代码:
      • 1.4、 AOP相关概念
    • 2、基于xml配置的AOP
      • 2.1、xml方式配置AOP的步骤:
      • 2.2、xml配置AOP的的细节:
        • 切点表达式举几个例子:
      • 2.2、通知方法在被调用时传递参数
          • JoinPoint 对象:
          • ProceedingJoinPoint
          • Throwable
      • 2.3、AOP的另一种配置方式: advisor 方式(了解即可):
      • 2.4、使用aspect和advisor配置区别如下:
    • 3、基于注解配置的AOP
      • 3.1、注解方式AOP基本使用
      • 3.2、各种注解方式通知类型
      • 3.3、切点表达式的抽取
    • 4、基于AOP的声明式事务控制

1、BeanFactory 快速入门

1.1、BeanFactory完成了loC思想的实现:

1)导入Spring相关的依赖:
<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.6</version>
        </dependency>
    </dependencies>
2)定义Uservice接口及其UserviceImpl实现类;

在这里插入图片描述

3)创建Bean的配置资源文件,文件名最好为:applicationContext.xml(规范),将UserServicelmpl的信息配置到该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="userService" class="cn.js.service.impl.UserServiceImpl"></bean>
</beans>
4)编写测试代码,创建BeanFactory,加载配置文件,获取UserService实例对象
1、通过工厂对象进行创建:
//1.创建工厂对象
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

//2.创建一个读取器,用于读取Bean 的资源文件(.xml文件)
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

//3、读取配置文件给工厂
reader.loadBeanDefinitions("applicationContext.xml");

//4、根据ID获取Bean实例对象
UserService userService = (UserService)beanFactory.getBean("userService");
System.out.println(userService);


在这里插入图片描述

2、直接从classpatch 路径去寻找配置文件创建资源对象(该方式已废弃了解即可)
//1、从ClassPath路径去寻找配置文件创建资源对象
Resource resource = new ClassPathResource("applicationContext.xml");

//2、根据资源对象创建Bean工厂对象
BeanFactory beanFactory = new XmlBeanFactory(resource);

//3、从SpringIoc容器中获取指定名称的对象
UserService userService = (UserService)beanFactory.getBean("userService");
System.out.println(userService);

在这里插入图片描述

上面使用BeanFactory完成了loC思想的实现,下面去实现以下DI依赖注入(setter方式):

1.2、使用BeanFactory通过setter方式去实现以下DI依赖注入:

1)定义UserDao接口及其UserDaolmpl实现类
public interface UserDao {}
public class UserDaoImpl implements UserDao {}
2)修改UserServicelmpl代码,添加一个setUserDao(UserDao userDao)用于接收注入的对象:
public class UserServiceImpl implements UserService {

    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        System.out.println("BeanFactory工厂调用该方法--》"+userDao);
        this.userDao=userDao;
    }
}
3)修改applicationContext.xml配置文件,定义UserService的中嵌入配置注入UserDao;
<?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="userService" class="cn.js.service.impl.UserServiceImpl">
        <property name="userDao" ref="UserDao"></property>
    </bean>
    
    <bean id="UserDao" class="cn.js.dao.impl.UserDaoImpl"></bean>
</beans>

在这里插入图片描述

4)修改测试代码,获得UserService时,setUserService方法执行了注入操作。
  		//1.创建工厂对象
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        //2.创建一个读取器,用于读取Bean 的资源文件(.xml文件)
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);

        //3、读取配置文件给工厂
        reader.loadBeanDefinitions("applicationContext.xml");

        //4、根据ID获取Bean实例对象
        UserService userService = (UserService)beanFactory.getBean("userService");
        System.out.println(userService);

        UserDao userdao = (UserDao)beanFactory.getBean("UserDao");
        System.out.println(userdao);
打个断点:此时userDao,已经被注入

在这里插入图片描述

在这里插入图片描述

2、ApplicationContext 快速入门(重要)

ApplicationContext 称为Spring容器,内部封装了BeanFactory,比BeanFactory功能更丰富更强大,使用ApplicationContext 进行开发时,xml配置文件的名称习惯写成applicationContext.xml;

2.1、ApplicationContext实现Ioc思想
1)前三步和BeanFactry相同
5)读取核心配置文件获取实例化容器对象
//创建ApplicationContext,加载配置文件,实例化容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//根据beanName获得容器中的Bean实例
UserService userService = (UserService) applicationContext.getBean("userService");
System.out.println(userService);

3、BeanFactory与ApplicationContext的关系:

1、 BeanFactory是Spring的早期接口,称为`Spring的Bean工厂`,ApplicationContext是后期更高级接口,称之为`Spring 容器`;  
2、 ApplicationContext在BeanFactory基础上对功能进行了扩展,例如: 监听功能、国际化功能等。BeanFactory的API更偏向底层,ApplicationContext的API大多数是对这些底层API的封装;
3、 Bean创建的主要逻辑和功能都被封装在BeanFactory中,ApplicationContext不仅继承了BeanFactory,而目ApplicationContext内部还维护着BeanFactorv的引用,所以,ApplicationContext与BeanFactorv既有继承关系,又有融合关系。
4、 Bean的初始化时机不同,原始BeanFactory是在首次调用getBean时才进行Bean的创建,而ApplicationContext则是配置文件加载,容器一创建就将Bean都实例化并初始化好

ApplicationContext除了继承了BeanFactory外,还继承了ApplicationEventPublisher (事件发布器)、ResouresPatternResolver (资源解析器)、MessageSource (消息资源)等。

但是ApplicationContext的核心功能还是BeanFactory。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、BeanFactory的继承体系

BeanFactory的继承体系

BeanFactory是核心接口,项目运行过程中肯定有具体实现参与,这个具体实现就是DefaultListableBeanFactory而ApplicationContext内部维护的Beanfactory的实现类也是它

在这里插入图片描述

在这里插入图片描述

5、ApplicationContext的继承体系

1.ApplicationContext的继承体系

只在Spring基础环境下,即只导入spring-context坐标时,此时ApplicationContext的继承体系

在这里插入图片描述

2.只在Spring基础环境下,常用的三个ApplicationContext作用如下:

实现类功能描述
ClassPathXmlApplicationContext加载类路径下的xml配置的ApplicationContext
FileSystemXmlApplicationContext加载磁盘路径下的xml配置的ApplicationContext
AnnotationConfigApplicationContext加载注解配置类的ApplicationContext

3.在Spring的web环境下,常用的两个ApplicationContext作用如下

实现类功能描述
XmIWebApplicationContextWeb环境下,加载类路径下的xml配置的ApplicationContext
AnnotationConfigWebApplicationContextWeb环境下,加载磁盘路径下的xml配置的ApplicationContext

2、基于XML的Spring应用

2.1、SpringBean的配置详解

Spring开发中主要是对Bean的配置,Bean的常用配置一览如下:

在这里插入图片描述

1)Bean的基础配置

例如:配置UserDaolmpl由Spring容器负责管理
<bean id="userDao" class="com.js.dao .impl.UserDaoImpl"/>

此时存储到Spring容器(singleObjects单例池) 中的Bean的beanName是userDao,值是UserDaolmpl对象,可以根据beanName获取Bean实例

applicationContext.getBean("userDao");//beanName:进入Spring容器将 bean id="userDao" 这个ID转换成beanname

如果不配置id,则Spring会把当前Bean实例的全限定名作为beanName

applicationContext.getBean("com.js.dao.impl.UserDaoImpl") ;

2) Bean的别名配置

可以为当前Bean指定多个别名,根据别名也可以获得Bean对象
<bean id="userDao" "uname="aaa,bbb" class="com.js.dao.impl.UserDaoImpl"/>

此时多个名称都可以获得UserDaolmpl实例对象

applicationContext.getBean("userDao");
applicationContext.getBean("aaa");
applicationContext.getBean("bbb");

3) Bean的范围配置

默认情况下,单纯的Spring环境Bean的作用范围有两个: Singleton和Prototype
  • singleton: 单例,默认值,Spring容器创建的时候,就会进行Bean的实例化,并存储到容器内部的单例池中每次getBean时都是从单例池中获取相同的Bean实例;

  • prototype: 原型,Spring容器初始化时不会创建Bean实例,当调用getBean时才会实例化Bean,每次getBean都会创建一个新的Bean实例。

在这里插入图片描述

4) Bean的延迟加载

当lazy-init设置为true时为延迟加载,也就是当Spring容器创建的时候,不会立即创建Bean实例,等待用到时再创建Bean实例并存储到单例池中去,后续在使用该Bean直接从单例池获取即可,本质上该Bean还是单例的

< bean id="userDao"  class="com.js.dao.impl.UserDaoImpl"  ulazy-init="true"/>

5)Bean的初始化和销毁方法配置

Bean在被实例化后,可以执行指定的初始化方法完成一些初始化的操作,Bean在销毁之前也可以执行指定的销毁方法完成一些操作,初始化方法名称和销毁方法名称通过

< bean id="userDao"class="com.js.dao.impl.UserDaoImpln" init-method="init"  destroy-method="destroy" />
public class UserDaoImpl implements UserDao {
	public UserDaoImpl(){System.out.println("UserDaoImpl创建了...");}
    public void init(){System.out.printn("初始化方法...");}
    public void destroy(){ System.out.println("销毁方法...");}
}

public static void main(String[] args){
	ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
    UserService userService = (UserService) applicationContext.getBean("userDao")
    System.out.printIn(userService);//--------->这个地方是不会调用销毁方法的,如果没有调用close方法,Spring在执行这句输出语句后,就已经销毁了,还没有来得及调用销毁方法,所以我们要显示的关闭容器
    applicationContext.close() ;//关闭容器
} 
扩展: 除此之外,我们还可以通过实现 lnitializingean 接口,完成一些Bean的初始化操作,如下
public class UserDaoImpl implements UserDao, InitializingBean {
    public UserDaoImpl() {System.out.println("userDaoImpl创建了...");}
    public void init(){System.out.println("初始化方法...");}
    public void destroy(){System.out.println("销毁方法...");}
    //执行时机早于init-method配置的方法
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean...");
    }
}

6)Bean的实例化配置

Bean的实例化配置:就是Spring 帮我们创建Bean

Spring的实例化方式主要如下两种:
  • 构造方式实例化: 底层通过构造方法对Bean进行实例化;

    • 1.1 使用空构造器
    • 1.2 使用有参构造器
  • 工厂方式实例化: 底层通过调用自定义的工厂方法对Bean进行实例化

构造方式实例化:

构造方式实例化Bean又分为无参构造方法实例化和有参构造方法实例化,Spring中配置的几乎都是无参构造该方式,此处不在述。下面讲解有参构造方法实例化Bean

//有参构造方法
public UserDaoImpl(String name){}

有参构造在实例化Bean时,需要参数的注入,通过标签,嵌入在标签内部提供构造参数,如下:

<bean id="userDao" class="com,js,dao implUserDaoImpl">
    <constructor-arg name="name" value="haohao"/>
</bean>
工厂方式实例化:

工厂方式实例化Bean,又分为如下三种:

  • 静态工厂方法实例化Bean

  • 实例工厂方法实例化Bean

  • 实现FactoryBean规范延迟实例化Bean

1) 、静态工厂方法实例化Bean

静态工厂方法实例化Bean,其实就是定义一个工厂类,提供一个静态方法用于生产Bean实例,在将该工厂类及其 静态方法配置给Spring即可

//工厂类
public class UserDaoFactoryBean {
//非静态工厂方法
public static UserDao getUserDao(String name){
//可以在此编写一些其他逻辑代码
return new UserDaoImpl();
 }
}
<bean id="userDao" class="com.js.factory.UserDaoFactoryBean" factorymethod="getUserDao">
<constructor-arg name="name" value="haohao"/>
</bean>

解释:

1.Spring容器看到factorymethod:时知道,不是将"com.js.factory.UserDaoFactoryBean"变成对象而是将内部的getUserDao方法的返回值,当成对象,将我们指定的id="userDao"
作为BeanName,存储到容器当中;

2.<constructor-arg>标签不仅仅是为构造方法传递参数,只要是为了实例化对象而传递的参数都可以通过<constructor-arg>标签完成,例如上面通过静态工厂方法实例化Bean所传递的参数也是要通过<constructor-arg>进行传递的

测试代码,直接通过ApplicationContext获得userDao即可:

ApplicationContext applicationContext = new ClassPathxmlApplicationContext("applicationContext.xml");
Object userDao = applicationContext.getBean("userDao");
System.out.println(userDao);

断点调试,UserDaoImpl实例对象会存在于单例池中:

在这里插入图片描述

作用:

1.引入一些第三方的jar包,交给Spring管理时;
2.创建摸个对象之前有一些其他操作;
2)、实例工厂方法:

​ 实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂 对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean;

//工厂类
public class UserDaoFactoryBean2 {
//非静态工厂方法
public UserDao getUserDao(String name){
//可以在此编写一些其他逻辑代码
return new UserDaoImpl();
}
}

​ 实例工厂方法,也就是非静态工厂方法产生Bean实例,与静态工厂方式比较,该方式需要先有工厂对象,在用工厂 对象去调用非静态方法,所以在进行配置时,要先配置工厂Bean,在配置目标Bean;

<!-- 配置实例工厂Bean -->
<bean id="userDaoFactoryBean2" class="com.js.factory.UserDaoFactoryBean2"/>
<!-- 配置实例工厂Bean的哪个方法作为工厂方法 -->
<bean id="userDao" factory-bean="userDaoFactoryBean2" factory-method="getUserDao">
<constructor-arg name="name" value="haohao"/>
</bean>

解释

"factory-bean":告诉Spring 容器,实例工厂对象是哪个
"factory-method":告诉Spring 容器,实例工厂对象中的方法是哪个

测试代码,直接通过ApplicationContext获得userDao即可:

ApplicationContext applicationContext = new ClassPathxmlApplicationContext("applicationContext.xml");
Object userDao = applicationContext.getBean("userDao");
System.out.println(userDao);

通过断点观察单例池singletonObjects,发现单例池中既有工厂Bean实例,也有目标Bean实例,且都是在Spring 容器创建时,就完成了Bean的实例化;

在这里插入图片描述

3)、Bean的实例化配置:

上面不管是静态工厂方式还是非静态工厂方式,都是自定义的工厂方法,Spring提供了FactoryBean的接口规范, FactoryBean接口定义如下:

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = “factoryBeanObjectType”;
    T getObject() throws Exception; //获得实例对象方法
    Class<?> getObjectType(); //获得实例对象类型方法

    default boolean isSingleton() {
		return true;
	}
}

1、定义工厂实现FactoryBean:

public class UserDaoFactoryBean3 implements FactoryBean<UserDao> {
    
    //返回Bean是谁
    public UserDao getObject() throws Exception {
    	return new UserDaoImpl();
    }
    
    //返回bean的类型是啥
	public Class<?> getObjectType() {
		return UserDao.class;
	}
}

2、配置FactoryBean交由Spring管理即可

<bean id="userDao" class="com.js.factory.UserDaoFactoryBean3"/>

3、 通过Spring容器根据beanName可以正常获得UserDaoImp

ApplicationContext applicationContext = new ClassPathxmlApplicationContext("applicationContext.xml");
Object userDao = applicationContext.getBean("userDao");
System.out.println(userDao);

通过断点观察发现Spring容器创建时,FactoryBean被实例化了,并存储到了单例池singletonObjects中,但是 getObject() 方法尚未被执行,UserDaoImpl也没被实例化,当首次用到UserDaoImpl时,才调用getObject() , 此工厂方式产生的Bean实例不会存储到单例池singletonObjects中,会存储到 factoryBeanObjectCache 缓存池 中,并且后期每次使用到userDao都从该缓存池中返回的是同一个userDao实例。

在这里插入图片描述

7)Bean的依赖注入配置

Bean的依赖注入有两种方式:
注入方式配置方式
通过Bean的set方法注入<property name="userDao" ref="userDao"/><br/><property name="userDao" value="haohao"/>
通过构造Bean的方法进行注入<constructor-arg name="name" ref="userDao"/><br/><constructor-arg name="name" value="haohao"/>

​ 其中,ref 是 reference 的缩写形式,翻译为:涉及,参考的意思,用于引用其他Bean的id。value 用于注入普通 属性值。

依赖注入的数据类型有如下三种:

​ ⚫ 普通数据类型,例如:String、int、boolean等,通过value属性指定。

​ ⚫ 引用数据类型,例如:UserDaoImpl、DataSource等,通过 ref 属性指定。

​ ⚫ 集合数据类型,例如:List、Map、Properties等。

一、通过Seet方法进行注入
1)对于list注入:
  1. 注入 List 集合 – 普通数据
<property name="strList">
    <list>
        <value>haohao</value>
        <value>miaomiao</value>
    </list>
</property>

2.注入 List 集合 – 引用数据

<property name="objList">
    <list>
        <bean class="com.js.dao.impl.UserDaoImpl"></bean>
        <bean class="com.js.dao.impl.UserDaoImpl"></bean>
        <bean class="com.js.dao.impl.UserDaoImpl"></bean>
    </list>
</property>

也可以直接引用容器中存在的Bean

<!--配置UserDao-->
<bean id="userDao" class="com.js.dao.impl.UserDaoImpl"/>
<bean id="userDao2" class="com.js.dao.impl.UserDaoImpl"/>
<bean id="userDao3" class="com.js.dao.impl.UserDaoImpl"/>
<!--配置UserService-->
<bean id="userService" class="com.js.service.impl.UserServiceImpl">
    <property name="objList">
        <list>
            <ref bean="userDao"></ref>
            <ref bean="userDao2"></ref>
            <ref bean="userDao3"></ref>
        </list>
    </property>
</bean>
5)、注入 Set 集合
//注入泛型为字符串的Set集合
public void setValueSet(Set<String> valueSet){
    valueSet.forEach(str->{
    System.out.println(str);
    });
}

//注入泛型为对象的Set集合
public void setObjSet(Set<UserDao> objSet){
    objSet.forEach(obj->{
    System.out.println(obj);
    });
}

<!-- 注入泛型为字符串的Set集合 -->
<property name="valueSet">
    <set>
        <value>muzi</value>
        <value>muran</value>
    </set>
</property>
<!-- 注入泛型为对象的Set集合 -->
<property name="objSet">
    <set>
        <ref bean="userDao"></ref>
        <ref bean="userDao2"></ref>
        <ref bean="userDao3"></ref>
    </set>
</property>
3)、注入 Map 集合

注入 Map <k,y>集合

//注入值为字符串的Map集合
public void setValueMap(Map<String,String> valueMap){
    valueMap.forEach((k,v)->{
    System.out.println(k+"=="+v);
    });
}

//注入值为对象的Map集合
public void setObjMap(Map<String,UserDao> objMap){
    objMap.forEach((k,v)->{
    System.out.println(k+"=="+v);
    });
}

<!--注入值为字符串的Map集合-->
<property name="valueMap">
    <map>
        <entry key="aaa" value="AAA" />
        <entry key="bbb" value="BBB" />
        <entry key="ccc" value="CCC" />
    </map>
</property>

<!--注入值为对象的Map集合-->
<property name="objMap">
    <map>
        <entry key="ud" value-ref="userDao"/>
        <entry key="ud2" value-ref="userDao2"/>
        <entry key="ud3" value-ref="userDao3"/>
    </map>
</property>
4)、注入 Properties 键值对
//注入Properties
public void setProperties(Properties properties){
    properties.forEach((k,v)->{
    	System.out.println(k+"=="+v);
    });
}
	
<property name="properties">
    <props>
        <prop key="xxx">XXX</prop>
        <prop key="yyy">YYY</prop>
    </props>
</property

以上的Bean的依赖注入配置为手动

扩展:自动装配方式

如果被注入的属性类型是Bean引用的话,那么可以在 标签中使用 autowire 属性去配置自动注入方式,属 性值有两个:

⚫ byName:通过属性名自动装配,即去匹配 setXxx 与 id=“xxx”(name=“xxx”)是否一致;

⚫ byType:通过Bean的类型从容器中匹配,匹配出多个相同Bean类型时,报错。

<bean id="userService" class="com.js.service.impl.UserServiceImpl"
autowire="byType">

2.2、Spring 的getBean方法

方法定义返回值和参数
Object getBean (String beanName)根据beanName从容器中获取Bean实例,要求容器中Bean唯一,返回值为Object,需要强转
T getBean (Class type)根据Class类型从容器中获取Bean实例,要求容器中Bean类型唯一,返回值为Class类型实例, 无需强转
T getBean (String beanName,Class type)根据beanName从容器中获得Bean实例,返回值为Class类型实例,无需强转
//根据beanName获取容器中的Bean实例,需要手动强转
UserService userService = (UserService) applicationContext.getBean("userService");
//根据Bean类型去容器中匹配对应的Bean实例,如存在多个匹配Bean则报错
UserService userService2 = applicationContext.getBean(UserService.class);
//根据beanName获取容器中的Bean实例,指定Bean的Type类型
UserService userService3 = applicationContext.getBean("userService",
UserService.class);

2.3、Spring 配置非自定义Bean

以上在 xml 中配置的Bean都是自己定义的,例如:UserDaoImpl,UserServiceImpl。但是,在实际开发中有些 功能类并不是我们自己定义的,而是使用的第三方jar包中的,那么,这些Bean要想让Spring进行管理,也需要对 其进行配置

配置非自定义的Bean需要考虑如下两个问题:

⚫ 被配置的Bean的实例化方式是什么?无参构造、有参构造、静态工厂方式还是实例工厂方式;

⚫ 被配置的Bean是否需要注入必要属性。

列子:

1)配置 Druid 数据源交由Spring管理

配置 DruidDataSource

<!--配置 DruidDataSource数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<!--配置必要属性-->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>

3、基于注解诞的Spring应用

1、Bean基本注解开发

基本Bean注解,主要是使用注解的方式替代原有xml的 标签及其标签属性的配置

<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method=""
abstract="" autowire="" factory-bean="" factory-method=""></bean>

使用@Component 注解替代标签

xml配置注解描述
@Component被该注解标识的类,会在指定扫描范围内被Spring加载并实例化

可以通过@Component注解的value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前 类名首字母小写

//获取方式:applicationContext.getBean("userDao");
@Component("userDao")//表示将当前这个Bean创建好的实例对象以指定的名称"userDao" BeanName存储到Spring容器当中
public class UserDaoImpl implements UserDao {
}
//获取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}

使用注解对需要被Spring实例化的Bean进行标注,但是需要告诉Spring去哪找这些Bean,要配置组件扫描路径

<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 告知Spring框架去js包及其子包下去扫描使用了注解的类 -->
<context:component-scan base-package="com.js"/>
</beans>

@Component就单纯一个value属性,那么xml配置 时那些属性怎么进行配置呢?Spring 是通过注解方 式去配置的之前 标签中的那些属性,例如:@Scope

<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method=""
abstract="" autowire="" factory-bean="" factory-method=""></bean>

使用@Component 注解替代标签

xml配置注解描述
@Scope在类上或使用了@Bean标注的方法上,标注Bean的作用范围,取值为 singleton或prototype
@Lazy在类上或使用了@Bean标注的方法上,标注Bean是否延迟加载,取值为 true和false
@PostConstruct在方法上使用,标注Bean的实例化后执行的方法
@PreDestroy在方法上使用,标注Bean的销毁前执行方法

使用上述注解完成UserDaoImpl的基本配置

@Component("userDao")
@Scope("singleton")
@Lazy(true)
public class UserDaoImpl implements UserDao{
    @PostConstruct
    public void init(){
        sout("初始方法");
    }
    @PreDestroy
    public void destroy(){
        sout("销毁方法")
    }
}

由于JavaEE开发是分层的,为了每层Bean标识的注解语义化更加明确,@Component又衍生出如下三个注解:

@Component衍生注解描述
@Repository在Dao层类上使用
@Service在Service层类上使用(标注在实现类上,因为接口无法直接实例化,只能找他实现类进行实现)
@Controller在Web层类上使用
@Repository("userDao")
public class UserDaoImpl implements UserDao{}
@Service("userService")
public class UserServiceImpl implements UserService{}
@Controller("userService")
public class UserController {}

2、Bean依赖注入注解开发

Bean依赖注入的注解,主要是使用注解的方式替代xml的 标签完成属性的注入操作

<bean id="" class="">
<property name="" value=""/>
<property name="" ref=""/>
</bean>

Spring主要提供如下注解,用于在Bean内部进行属性注入的:

属性注入注解描述
@Value使用在字段或方法上,用于注入普通数据
@Autowired使用在字段或方法上,用于根据类型(byType)注入引用数据
@Qualifier使用在字段或方法上,结合@Autowired,根据名称注入
@Resource使用在字段或方法上,根据类型或名称进行注入

1)、@Value

通过@Value 直接注入普通属性

@Value("haohao")
private String username;
@Value("haohao")
public void setUsername(String username){
System.out.println(username);
}

通过@Value 注入properties文件中的属性

@Value("${jdbc.username}")
private String username;
@Value("${jdbc.username}")
public void setUsername(String username){
System.out.println(username);
}

加载properties文件

<context:property-placeholder location="classpath:jdbc.properties"/>

2)、@Autowired注解

@Autowired注解,用于根据类型进行注入,如果同一类型的Bean有多个,尝试根据名字进行二次匹配,不匹配时会报错

//1、使用在属性上直接注入:
@Autowired
private UserDao userDao;


//2、使用在方法上直接注入,他是根据参数类型进行匹配的,方法名可以不是set方法开头的,
@Autowired
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}

当容器中同一类型的Bean实例有多个时,会尝试自动根据名字进行匹配:

//匹配当前Bean
@Repository("userDao")
public class UserDaoImpl implements UserDao{}
@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{}

当容器中同一类型的Bean实例有多个时,且名字与被注入Bean名称不匹配时会报错

@Qualifier配合@Autowired可以完成根据名称注入Bean实例,使用@Qualifier指定名称

@Autowired
@Qualifier("userDao2")
private UserDao userDao;
@Autowired
@Qualifier("userDao2")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}

3)、@Resource注解

@Resource注解既可以根据类型注入,也可以根据名称注入,无参就是根据类型注入,有参数就是根据名称注入

@Resource
private UserDao userDao;
@Resource(name = "userDao2")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}

@Resource注解存在与 javax.annotation 包中,Spring对其进行了解析

3、非自定义Bean注解开发

非自定义Bean不能像自定义Bean一样使用@Component进行管理,非自定义Bean要通过工厂的方式进行实例化, 使用@Bean标注方法即可,@Bean的属性为beanName,如不指定为当前工厂方法名称

//将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")//参数就是BeanName,没有加,以方法名设置为BeanName
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    return dataSource;
}

**注意:**工厂方法所在类必须要被Spring管理

如果@Bean工厂方法需要参数的话,则有如下几种注入方式:

⚫ 使用@Autowired 根据类型自动进行Bean的匹配,@Autowired可以省略 ;

⚫ 使用@Qualifier 根据名称进行Bean的匹配;

⚫ 使用@Value 根据名称进行普通数据类型匹配

@Bean
@Autowired //根据类型匹配参数
public Object objectDemo01(UserDao userDao){
    System.out.println(userDao);
    return new Object();
}

@Bean
public Object objectDemo02(@Qualifier("userDao") UserDao userDao,@Value("${jdbc.username}") String username){
    System.out.println(userDao);
    System.out.println(username);
    return new Object();
}

4、Bean配置类的注解开发

Bean配置类的注解开发,是使用配置类替代Spring配置文件applicationContext.xml 文件的

@Component等注解替代了标签,但是像、< context:componentScan> 等非 标签怎 样去使用注解替代呢?

<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 组件扫描 -->
<context:component-scan base-package="com.js"/>
<!-- 引入其他xml文件 -->
<import resource="classpath:beans.xml"/>

定义一个配置类替代原有的xml配置文件,标签以外的标签,一般都是在配置类上使用注解完成的

@Configuration是个组合注解,该注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,第 二个作用是具备@Component作用

@Configuration
public class ApplicationContextConfig {}

@ComponentScan 组件扫描配置,替代原有xml文件中的 <context:component-scan base-package=“”/>

@Configuration
@ComponentScan({"com.js.service","com.js.dao"})
public class ApplicationContextConfig {}

base-package的配置方式:

⚫ 指定一个或多个包名:扫描指定包及其子包下使用注解的类

⚫ 不配置包名:扫描当前@componentScan注解配置类所在包及其子包下的类

@PropertySource 注解用于加载外部properties资源配置,替代原有xml中的<<context:propertyplaceholder location=" "> 配置

@Configuration
@ComponentScan
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class ApplicationContextConfig {}

@Import 用于加载其他配置类,替代原有xml中的配置

@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
@Import(OtherConfig.class)
public class ApplicationContextConfig {}

4、Spring Aop

1、AOP 简介

1.1、AOP的概念

​ AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个 事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属 性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程

在这里插入图片描述

1.2、AOP思想的实现方案

动态代理技术,在运行期间,对目标对象 的方法进行增强,代理对象同名方法内可 以执行原有逻辑的同时嵌入执行其他增强 逻辑或其他对象的方法

在这里插入图片描述

1.3、Aop简介

模拟AOP的基础代码 其实在之前学习BeanPostProcessor时,在BeanPostProcessor的after方法中使用动态代理对Bean进行了增 强,实际存储到单例池singleObjects中的不是当前目标对象本身,而是当前目标对象的代理对象Proxy,这样 在调用目标对象方法时,实际调用的是代理对象Proxy的同名方法,起到了目标方法前后都进行增强的功能, 对该方式进行一下优化,将增强的方法提取出去到一个增强类中,且只对com.js.service.impl包下的任 何类的任何方法进行增强

//自定义增强类
public class MyAdvice {
public void beforeAdvice(){
System.out.println("beforeAdvice ...");
}
public void afterAdvice(){
System.out.println("afterAdvice ...");
}
}
模拟AOP的基础代码:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContextAware;

public class MockAopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
    private ApplicationContext applicationContext;//注入Spring容器对象

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);//获得Advice对象
        String packageName = bean.getClass().getPackage().getName();
        if ("com.js.service.impl".equals(packageName)) {
//对Bean进行动态代理,返回的是Proxy代理对象
            Object proxyBean = Proxy.newProxyInstance(
                    bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    (Object proxy, Method method, Object[] args) -> {
                        myAdvice.beforeAdvice();//执行Advice的before方法
                        Object result = method.invoke(bean, args);//执行目标
                        myAdvice.afterAdvice();//执行Advice的after方法
                        return result;
                    });
//返回代理对象
            return proxyBean;
        }
        return bean;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

1.4、 AOP相关概念

在这里插入图片描述

在这里插入图片描述

2、基于xml配置的AOP

xml方式AOP快速入门 前面我们自己编写的AOP基础代码还是存在一些问题的,主要如下:

⚫ 被增强的包名在代码写死了

⚫ 通知对象的方法在代码中写死了

通过配置文件的方式去解决上述问题

⚫ 配置哪些包、哪些类、哪些方法需要被增强

⚫ 配置目标方法要被哪些通知方法所增强,在目标方法执行之前还是之后执行增强 配置方式的设计、配置文件(注解)的解析工作,Spring已经帮我们封装好了

2.1、xml方式配置AOP的步骤:

1、导入AOP相关坐标;

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>


2、准备目标类、准备增强类,并配置给Spring管理;

目标类增强类
public interface UserService { void show1(); void show2(); } public class UserServiceImpl implements UserService { public void show1() { System.out.println(“show1…”); } public void show2() { System.out.println(“show2…”); }}public class MyAdvice { public void beforeAdvice(){ System.out.println(“beforeAdvice”); } public void afterAdvice(){ System.out.println(“afterAdvice”); } }
<!--配置目标类,内部的方法是连接点-->
<bean id="userService" class="com.js.service.impl.UserServiceImpl"/>
<!--配置通知类,内部的方法是增强方法-->
<bean id=“myAdvice" class="com.js.advice.MyAdvice"/>

3、配置切点表达式(哪些方法被增强);

4、配置织入(切点被哪些通知方法增强,是前置增强还是后置增强)。

<aop:config>
<!--配置切点表达式,对哪些方法进行增强-->
<aop:pointcut id="myPointcut" expression="execution(void
com.js.service.impl.UserServiceImpl.show1())"/>
<!--切面=切点+通知-->
<aop:aspect ref="myAdvice">
<!--指定前置通知方法是beforeAdvice-->
<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
<!--指定后置通知方法是afterAdvice-->
<aop:after-returning method="afterAdvice" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config

在这里插入图片描述

第二种:(提出到外面)

在这里插入图片描述

2.2、xml配置AOP的的细节:

⚫ 切点表达式的配置方式

​ 切点表达式的配置方式有两种,直接将切点表达式配置在通知上,也可以将切点表达式抽取到外面,在通知上 进行引用:

<aop:config>
<!--配置切点表达式,对哪些方法进行增强-->
<aop:pointcut id="myPointcut" expression="execution(void
com.js.service.impl.UserServiceImpl.show1())"/>
<!--切面=切点+通知-->
<aop:aspect ref="myAdvice">
<!--指定前置通知方法是beforeAdvice-->
<aop:before method="beforeAdvice" pointcut-ref="myPointcut"/>
<!--指定后置通知方法是afterAdvice-->
<aop:after-returning method="afterAdvice" pointcut="execution(void
com.js.service.impl.UserServiceImpl.show1())"/>
</aop:aspect>
</aop:config>

⚫ 切点表达式的配置语法

​ 切点表达式是配置要对哪些连接点(哪些类的哪些方法)进行通知的增强,语法如下:

execution([访问修饰符]返回值类型 包名.类名.方法名(参数))

其中:

  • 访问修饰符可以省略不写;

  • 返回值类型、某一级包名、类名、方法名 可以使用 * 表示任意;

  • 包名与类名之间使用单点 . 表示该包下的类,使用双点 … 表示该包及其子包下的类;

  • 参数列表可以使用两个点 … 表示任意参数

切点表达式举几个例子:
//表示访问修饰符为public、无返回值、在com.itheima.aop包下的TargetImpl类的无参方法show
execution(public void com.itheima.aop.TargetImpl.show())
//表述com.itheima.aop包下的TargetImpl类的任意方法
execution(* com.itheima.aop.TargetImpl.*(..))
//表示com.itheima.aop包下的任意类的任意方法
execution(* com.itheima.aop.*.*(..))
//表示com.itheima.aop包及其子包下的任意类的任意方法
execution(* com.itheima.aop..*.*(..))
//表示任意包中的任意类的任意方法
execution(* *..*.*(..))

⚫ 通知的类型

通知名称配置方式执行时机
前置通知< aop:before >目标方法执行之前执行
后置通知< aop:after-returning >目标方法执行之后执行,目标方法异常时,不在执行
环绕通知< aop:around >目标方法执行前后执行,目标方法异常时,环绕后方法不在执行
异常通知< aop:after-throwing >目标方法抛出异常时执行
最终通知< aop:after >不管目标方法是否有异常,最终都会执行

⚫ AOP的配置的方式(aspect)

  • 环绕通知
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    //环绕前
    System.out.println("环绕前通知");
    //目标方法
    joinPoint.proceed();
    ///环绕后
    System.out.println("环绕后通知");
}

<aop:around method="around" pointcut-ref="myPointcut"/>
  • 异常通知

异常通知,当目标方法抛出异常时,异常通知方法执行,且后置通知和环绕后通知不在执行

public void afterThrowing(){
System.out.println("目标方法抛出异常了,后置通知和环绕后通知不在执行");
}
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
  • 最终通知

最终通知,类似异常捕获中的finally,不管目标方法有没有异常,最终都会执行的通知

public void after(){
System.out.println("不管目标方法有无异常,我都会执行");
}
<aop:after method="after" pointcut-ref="myPointcut"/>

2.2、通知方法在被调用时传递参数

参数类型作用
JoinPoint连接点对象,任何通知都可使用,可以获得当前目标对象、目标方法参数等信息
ProceedingJoinPointJoinPoint子类对象,主要是在环绕通知中执行proceed(),进而执行目标方法
Throwable异常对象,使用在异常通知中,需要在配置文件中指出异常对象名称
  • JoinPoint 对象:
public void 通知方法名称(JoinPoint joinPoint){
    //获得目标方法的参数
    System.out.println(joinPoint.getArgs());
    //获得目标对象
    System.out.println(joinPoint.getTarget());
    //获得精确的切点表达式信息
    System.out.println(joinPoint.getStaticPart());
}
  • ProceedingJoinPoint
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println(joinPoint.getArgs());//获得目标方法的参数
    System.out.println(joinPoint.getTarget());//获得目标对象
    System.out.println(joinPoint.getStaticPart());//获得精确的切点表达式信息
    Object result = joinPoint.proceed();//执行目标方法
    return result;//返回目标方法返回值
}

  • Throwable

在这里插入图片描述

2.3、AOP的另一种配置方式: advisor 方式(了解即可):

AOP的另一种配置方式,该方式需要通知类实现Advice的子功能接口 Advice的子功能接口

public interface Advice {
}

Advice的子功能接口:

在这里插入图片描述

例如:通知类实现了前置通知和后置通知接口

public class Advices implements MethodBeforeAdvice, AfterReturningAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
	System.out.println("This is before Advice ...");
  }

public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws
  Throwable {
      System.out.println("This is afterReturn Advice ...");
   }
}

切面使用advisor标签配置:不用指定通知方式,而是以实现的接口中的方法,来执行

<aop:config>
<!-- 将通知和切点进行结合 -->
<aop:advisor advice-ref="advices" pointcut="execution(void com.js.aop.TargetImpl.show())"/>
</aop:config>

又例如:通知类实现了方法拦截器接口

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
    System.out.println("前置逻辑功能...");
    //执行目标方法
    Object invoke =
    methodInvocation.getMethod().invoke(methodInvocation.getThis(),methodInvocation.getArguments());
    System.out.println("后置逻辑功能...");
    return invoke;
    }
}

切面使用advisor标签配置

<aop:config>
<!-- 将通知和切点进行结合 -->
<aop:advisor advice-ref=“myMethodInterceptor" pointcut="execution(void
com.itheima.aop.TargetImpl.show())"/>
</aop:config>

2.4、使用aspect和advisor配置区别如下:

  • 配置语法不同:
<!-- 使用advisor配置 -->
<aop:config>
<!-- advice-ref:通知Bean的id -->
<aop:advisor advice-ref="advices" pointcut="execution(void
com.itheima.aop.TargetImpl.show())"/>
</aop:config>
<!-- 使用aspect配置 -->
<aop:config>
<!-- ref:通知Bean的id -->
<aop:aspect ref="advices">
<aop:before method="before" pointcut="execution(void
com.itheima.aop.TargetImpl.show())"/>
</aop:aspect>
</aop:config>
  • 通知类的定义要求不同,advisor 需要的通知类需要实现Advice的子功能接口:
public class Advices implements MethodBeforeAdvice {
public void before(Method method, Object[] objects, Object o) throws Throwable {
	System.out.println("This is before Advice ...");
}
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws
    Throwable {
    System.out.println("This is afterReturn Advice ...");
    }
}

aspect 不需要通知类实现任何接口,在配置的时候指定哪些方法属于哪种通知类型即可,更加灵活方便:

public class Advices {
public void before() {
	System.out.println("This is before Advice ...");
}
    public void afterReturning() {
    System.out.println("This is afterReturn Advice ...");
    }
}
  • 可配置的切面数量不同:

    • 一个advisor只能配置一个固定通知和一个切点表达式;
    • 一个aspect可以配置多个通知和多个切点表达式任意组合,粒度更细。
  • 使用场景不同:

    • 如果通知类型多、允许随意搭配情况下可以使用aspect进行配置;
    • 如果通知类型单一、且通知类中通知方法一次性都会使用到的情况下可以使用advisor进行配置;
    • 在通知类型已经固定,不用人为指定通知类型时,可以使用advisor进行配置,例如后面要学习的Spring事务 控制的配置;

由于实际开发中,自定义aop功能的配置大多使用aspect的配置方式,所以我们后面主要讲解aspect的配置, advisor是为了后面Spring声明式事务控制做铺垫,此处大家了解即可。

3、基于注解配置的AOP

3.1、注解方式AOP基本使用

目标类被Spring容器管理、通知类被Spring管理

@Component("target")
public class TargetImpl implements Target{
    public void show() {
      System.out.println("show Target running...");
    }
}
@Component
public class AnnoAdvice {
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕前通知...");
    joinPoint.proceed();
    System.out.println("环绕后通知...");
    }
}

配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么

@Component
@Aspect //第一步
public class AnnoAdvice {
@Around("execution(* com.itheima.aop.*.*(..))") //第二步
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("环绕前通知...");
    joinPoint.proceed();
    System.out.println("环绕后通知...");
    }
}

在这里插入图片描述

注解@Aspect、@Around需要被Spring解析,所以在Spring核心配置文件中需要配置aspectj的自动代理

<aop:aspectj-autoproxy/>

配置aop,其实配置aop主要就是配置通知类中的哪个方法(通知类型)对应的切点表达式是什么

在这里插入图片描述

如果核心配置使用的是配置类的话,需要配置注解方式的aop自动代理

@Configuration
@ComponentScan("com.itheima.aop")
@EnableAspectJAutoProxy //第三步
public class ApplicationContextConfig {
}

3.2、各种注解方式通知类型

//前置通知
@Before("execution(* com.itheima.aop.*.*(..))")
public void before(JoinPoint joinPoint){}
//后置通知
@AfterReturning("execution(* com.itheima.aop.*.*(..))")
public void AfterReturning(JoinPoint joinPoint){}
//环绕通知
@Around("execution(* com.itheima.aop.*.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {}
//异常通知
@AfterThrowing("execution(* com.itheima.aop.*.*(..))")
public void AfterThrowing(JoinPoint joinPoint){}
//最终通知
@After("execution(* com.itheima.aop.*.*(..))")
public void After(JoinPoint joinPoint){}

3.3、切点表达式的抽取

@Component
@Aspect
public class AnnoAdvice {
    //切点表达式抽取
    @Pointcut("execution(* com.itheima.aop.*.*(..))")
    public void pointcut(){}
    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){}
    //后置通知
    @AfterReturning("AnnoAdvice.pointcut()")
    public void AfterReturning(JoinPoint joinPoint){}
    // ... 省略其他代码 ...
}

4、基于AOP的声明式事务控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1825230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows 服务器Nginx 下载、部署、配置流程(图文教程)

不定期更新 目录 一、下载Nginx安装包 二、上传安装包 三、启动Nginx 四、Nginx常用命令 五、Nginx&#xff08;最小&#xff09;配置详解 六、Nginx&#xff08;基础&#xff09;配置详解 七、反向代理 八、负载均衡 九、动静分离 十、报错 一、下载Nginx安装包 四…

论文阅读笔记:Cross-Image Relational Knowledge Distillation for Semantic Segmentation

论文阅读笔记&#xff1a;Cross-Image Relational Knowledge Distillation for Semantic Segmentation 1 背景2 创新点3 方法4 模块4.1 预备知识4.2 跨图像关系知识蒸馏4.3 Memory-based像素到像素蒸馏4.4 Memory-based像素到区域蒸馏4.5 整体框架 5 效果 论文&#xff1a;http…

chatgpt的命令词

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Pycharm社区版搭建Django环境及Django简单项目、操控mysql数据库

Web应用开发&#xff08;Django&#xff09; 一、配置Django环境 1、先通过Pycharm社区版创建一个普通的项目 2、依次点击”file"-->"Settings" 3、点击"Project:项目名"-"Python Interpreter"-"号" 4、在搜索框输入要安装的…

解决方案︱视频孪生智慧高速解决方案

系统概述 在交通强国战略的指导下&#xff0c;我国政府高度重视以数字化为核心的智慧高速公路建设与发展。2023年9月&#xff0c;交通运输部印发了《交通运输部关于推进公路数字化转型加快智慧公路建设发展的意见》&#xff0c;强调到2035年&#xff0c;全面实现公路数字化转型…

高清视频+AI算法,EasyCVR视频智能监控方案打造无死角吸烟行为检测

一、背景与意义 1、吸烟危害&#xff1a;吸烟不仅有害健康&#xff0c;而且在特定场所带来的安全隐患极大。据统计&#xff0c;全年火灾事故中有五分之一系抽烟引起&#xff0c;引发的人员伤亡和财产损失巨大。 2、政策与法规&#xff1a;为了保护公共安全&#xff0c;消除消…

机器学习:人工智能的子领域之一

引言 人工智能&#xff08;AI&#xff09;已经成为现代科技的重要组成部分&#xff0c;推动了许多领域的创新与进步。在人工智能的诸多子领域中&#xff0c;机器学习&#xff08;ML&#xff09;无疑是最关键和最具影响力的一个。机器学习通过自动分析和学习数据中的模式&#x…

大数据技术学习回顾01-大数据的特点、技术体系(三驾马车)

参考来源&#xff1a; 极客时间专栏&#xff1a;从0开始学大数据&#xff0c;作者&#xff1a;李智慧 大数据技术整体概览 大数据技术体系 大数据处理的主要应用场景包括数据分析、数据挖掘与机器学习。数据分析主要使用 Hive、Spark SQL 等 SQL 引擎完成&#xff1b;数据挖…

【Python系列】Python 中的日期和时间处理

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

SSM家乡旅游网-计算机毕业设计源码04802

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;SSM家乡旅游网当然也不能排除在外。SSM家乡旅游网是以实际运用为开发背景&#xff0c;运用软件工程开发方法&#xff0c…

U-Mail邮件系统全面支持信创国产化,打造自主可控的邮件系统

长期以来&#xff0c;中国IT产业的底层架构和标准多由国际巨头所主导&#xff0c;这不仅限制了本土技术的创新发展&#xff0c;同时也给国家安全带来了潜在的挑战。为了应对这一现状&#xff0c;我国正逐步构建起一套独立且安全的IT生态系统&#xff0c;旨在实现技术的自主可控…

论文学习day01

1.自我反思的检索增强生成&#xff08;SELF-RAG&#xff09; 1.文章出处&#xff1a; Chan, C., Xu, C., Yuan, R., Luo, H., Xue, W., Guo, Y., & Fu, J. (2024). RQ-RAG: Learning to Refine Queries for Retrieval Augmented Generation. ArXiv, abs/2404.00610. 2.摘…

快速上手SpringBoot

黑马程序员Spring Boot2 文章目录 1、SpringBoot 入门程序开发1.1 创建一个新的项目 2、浅谈入门程序工作原理2.1 parent2.2 starter2.3 引导类2.4 内嵌tomcat 1、SpringBoot 入门程序开发 1.1 创建一个新的项目 file > new > project > empty Project 创建新模块&a…

如何在 Vue 3 中使用 vue3-print-nb 实现灵活的前端打印

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 前言 在前端开…

Linux中Web服务器配置和管理(Apache)

文章目录 一、WEB服务器介绍1.1、WEB服务器概述1.2、WEB服务器的发展历史1.3、WEB服务器的优点与缺点1.4、WEB服务器的工作流程 二、Apache介绍2.1、Apache是什么2.2、Apache的发展史与应用场景2.3、Apache的特点2.4、Apache的工作原理2.5、Apache的模块 三、安装使用Apache服务…

iOS 18 中全新 SwiftData 重装升级,其中一个功能保证你们“爱不释手”

概览 在最新的 WWDC 2024 中&#xff0c;苹果对多个系统框架都做了重量级的功能升级。这怎么能够少了 SwiftData 这位“后起之秀”呢&#xff1f; 万象更新的 iOS 18 为 SwiftData 增加了全新的唯一性、自定义数据仓库、富表达式以及字段索引等超赞功能。 在本篇博文中&#…

论文中引用网页链接的简单操作

一、参考资料 中文论文或者申请书中网页新闻引用格式 自制网页&#xff1a;在论文中快速引用网页链接 二、相关介绍 1. 常用文献类型用单字母标识 学术论文参考文献中文献类型字母标识 常用文献类型用单字母标识&#xff0c;具体如下&#xff1a; &#xff08;1&#xf…

自动控制理论---线性时不变系统的单位脉冲响应

1、实验设备 PC计算机1台&#xff0c;MATLAB软件1套。 2.实验目的&#xff1a; 学习并理解线性时不变系统的单位脉冲响应的计算方法。掌握MATLAB编程&#xff0c;计算整个系统的单位脉冲响应。 3.实验原理说明&#xff1a; 单位脉冲响应是指在输入信号为单位脉冲序列时&am…

【Java】内部类、枚举、泛型

目录 1.内部类1.1概述1.2分类1.3匿名内部类(重点) 2.枚举2.1一般枚举2.2抽象枚举2.3应用1&#xff1a;用枚举写单例2.4应用2&#xff1a;标识常量 3.泛型3.1泛型认识3.2泛型原理3.3泛型的定义泛型类泛型接口泛型方法 3.4泛型的注意事项 1.内部类 1.1概述 内部类&#xff1a;指…

高分文章发文圣体!一周80%二区以上 | GBD数据库周报(6.05~6.11)

全球疾病负担&#xff08;GBD&#xff09;是迄今为止规模最大、最全面的一项研究&#xff0c;旨在量化不同地区和不同时期的健康损失&#xff0c;从而改善卫生系统并消除差异。 该研究由华盛顿大学健康指标与评估研究所 (IHME) 牵头&#xff0c;是一项真正的全球性研究&#xf…