SSM-Spring

69 阅读11分钟

一、Spring

image.png

  • Core Container:核心容器
  • Aspects:AOP思想实现
  • AOP:面向切面
  • Data Integration:数据集成
  • Data Access:数据访问
  • Test:单元测试与集成测试

快速入门

  • IoC(Inversion of Control)控制反转

    • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
  • Spring技术对IoC思想进行了实现

    • 由Spring提供了一个容器,称为IoC容器,来充当IoC思想中的"外部"
    • IoC容器负责对象的创建,初始化等一系列,被创建或被管理的对象在IoC容器中统称为Bean
  • DI(Dependency Injection)依赖注入

    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
  • 目标: 充分解耦

    • 使用IoC容器管理bean(IoC)
    • 在IoC容器内将有依赖关系的bean进行关系绑定(DI)
  • 最终效果

    • 使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系

入门案例

  1. 基于IoC管理bean
  2. Service中使用new形式创建的Dao对象是否保留?(否)
  3. Service中需要的Dao对象如何进入到Service中?【使用依赖注入】(提供方法)
  4. Service与Dao间的关系如何描述?(配置)【一个业务层可以控制很多数据层】
//步骤1:将业务层中的new的DAO对象删除,使用set方法实现

public class BookServiceImpl implements BookService{
	private BookDao;
	public void save(){
		bookDao.save();
	}
    //提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
        System.out.println("提供了对应的set方法");
    } 
}
<!--步骤2:配置bean进行依赖注入,使用property标签注册一个属性-->
<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hcx.service.impl.BookServiceImpl">
	<!--配置dao与service的关系-->
    <property name="bookDao" ref="bookDao"/>
</bean>

使用Spring的API获得Bean实例

public class UseDaoDemo {
    public static void main(String[] args) {
        ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) app.getBean("userDao");
        userDao.save();
    }
}

二、Bean相关配置

Bean的别名

在application.xml起别名,或取多个别名,【用空格,或者逗号,或者分号分隔开来】

ref属性既可以引用id也可以引用name,getBean可使用别名

<bean id="bookDao" name="dao dao2" class="com.hcx.dao.impl.BookDaoImpl"/>
<bean id="bookService" name="service" class="com.hcx.service.impl.BookServiceImpl">
	<!--配置dao与service的关系-->
    <property name="bookDao" ref="dao"/>
</bean>

scope:指对象的作用范围

image.png 在这里插入图片描述
在这里插入图片描述

  • 为什么bean默认的是单例的?

​ ---便于管理复用对象,提高效率

  • 适合交给容器进行管理的bean

    • 封装实体的域对象(有状态的)

Bean的生命周期

  • 生命周期:从创建到消亡的完整过程

  • bean生命周期:bean从创建到销毁的整体过程

  • bean生命周期控制:在bean创建后到销毁前做一些事情

  • 配置

    • init-method
    • destory-method
public void init(){
    System.out.print("Bean初始化操作");
}
public void destory(){
    System.out.print("Bean销毁操作");
}
<bean id="bookDao" class="com.hcx.impl.BookDaoImpl" init-method="init" destory-method="destory"/>
//无法调用销毁方式原因,JVM直接退出,未执行关闭ClassPathXmlApplicationContext对象
eg:
// 不用 ApplicationContext接口下ClassPathXmlApplication实现类型下的close()方法 ,还可以使用使用ApplicationContext下的实现类AnnotationConfigApplicationContext()实现下的close()方法
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao =(BookDao) context.getBean("bookDao");
//暴力方法
context.close();
//灵巧方法
context.registerShutdownHook();
  • 接口

    • InitializingBean
    • DisposableBean
//bean生命周期,标准实现方式,实现InitializingBean, DisposableBean两个接口中的方法
eg:
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    //    删除业务层中使用new的方式创建dao对象
//    private BookDao bookDao = new BookDaoImpl();
    private BookDao bookDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    //提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
        System.out.println("提供了对应的set方法");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("service destory");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}

Bean实例化方式

  • Bean本质上就是对象,创建bean使用构造方法完成

方法一:构造方法实现Bean

//首先在application中注册bean
//其次在实现类中实现构造方法实例化实现类
private BookDaoImpl(){
	System.out.println("Book is constructor is running ...");
}
//无论是使用private还是public都能访问到构造方法,利用到了反射
//无参构造方法是默认实现
<bean id="bookkDao" class="com.hcx.dao.impl.BookDaoImpl"/>

方法二:使用静态工厂

//新建一个静态工厂
public class OrderDaoFactory{
public static OrderDao getOrderDao(){
    return new OrderDaoImpl();
	}
}
//实例化对象时getBean()方法调用静态工厂实例化对象
<bean id="orderDao" class="com.hcx.factory.OrderDaoFactory" factory-method="getOrderDao"/>

方法三:实例工厂

public class AppForInstanceUser{
	public static void main(String[] args){
        //创建实例静态工厂对象
        UserDaoFactory userDaoFactroy = new UserDaoFactory();
        //通过实例工厂对象创建对象
        User userDao = userDaoFactory.getUserDao();
        userDao.save();
    }
}

public class UserDaoFactory{
    public UserDao getUserDao(){
        retrun new UserDaoImpl();
    }
}
<bean id="userFactory" class="com.hcx.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

方式四:FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao>{
    public UserDao getObject() throws Expection{
        return new UserDaoImpl();
    }
    public Class<?> getObjectType(){
        return UserDao.class;
    }
}
<bean id="userDao" class="com.hcx.factory.UserDaoFactoryBean"/>

依赖注入方式

1)set方法注入

引用类型

  • 在bean中定义引用类型属性并提供可访问的set方法

    public class BookServiceImpl implements BookService(
    	private BookDao bookDao;
        public void setBookDao(BookDao bookDao){
            this.bookDao = bookDao;
        }
    )
    
  • 配置中使用property标签ref属性注入引用类型对象

    <bean id="bookService" class="com.hcx.service.impl.BookServiceImpl">
    	<property name="bookDao" ref="bookDao"/>
    </bean>
    <bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl"/>
    

简单类型

  • 在bean中定义简单类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao(
	private int connectionNum;
	private String databaseName;
	public void setConnectionNum(int connectionNum){
        this.connectionNum=connectionNum;
    }
    public void setDatabaseName(String databaseName){
        this.databaseName=datanaseName;
    }
)
  • 配置中使用property标签value属性注入基本类型对象
<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl">
	<property name="connectionNum" value="100"/>
    <property name="databaseName" value="MySql"/>
</bean>

2)构造方法注入

引用类型

  • 在bean中定义引用类型属性并提供可访问的构造方法
public class BookServiceImpl implements BookService(
	private BookDao bookDoa;
    public BookServiceImpl(BookDao bookDao){
        this.bookDao = bookDao;
    }
)
   
  • 配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.hcx.service.impl.BookServiceImpl">
	<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl"/>

构造器注入——简单类型

  • 在bean中定义引用类型属性并提供可访问的set方法
public class BookDaoImpl implements BookDao{
	private int connectionNumber;
    public BookDaoImpl(int connectionNumber){
   		this.connectionNumber = connectionNumber;
    }
}
  • 在配置中使用constructor-arg标签value属性注入简单数据类型
<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl">
	<constructor-arg name="connectionNumber" value="10"/>
</bean>

参数设置

  • 配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
	<constructor-arg type="int" value="10"/>
	<constructor-arg type="java.lang.String" value="mysql"/> 
</bean>
  • 配置中使用constructor-arg标签index属性设置按形参位置注入
<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl">
	<constructor-arg index="0" value="10"/>
	<constructor-arg index="1" value="MYSQL"/>
</bean>

依赖自动装配

  • oC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称之为自动装配

  • 自动装配方式

    • 按类型(常用)
    • 按名称
    • 按构造方法
    • 不启用自动装配
  • 配置中使用bean标签autowire属性设置自动装配的类型

**

<bean id="bookDao" class="com.hcx.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hcx.service.impl.BookServiceImpl" autowire="byType"/>
  • 自动装配用于引用类型依赖注入,不能对简单类型进行操作
  • 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  • 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名和配置耦合,不推荐使用
  • 自动装配优先级低于setter注入和构造器注入,同时出现时自动装配失效

集合注入 数据类型:

数组

<property name="array">
	<array>
		<value>100</value>
		<value>200</value>
		<value>300</value>
	</array>
</property>

List

<property name="list">
            <list>
                <value>加油</value>
                <value>每天</value>
                <value>学习</value>
            </list>
</property>

Set

<property name="set">
            <set>
                <value>好好</value>
                <value>工作</value>
                <value>跑路</value>
            </set>
</property>

Map

<property name="map">
            <map>
                <entry key="country" value="china"></entry>
                <entry key="city" value="成都"></entry>
                <entry key="province" value="四川"></entry>
            </map>
</property>

Properties

<property name="properties">
            <props>
                <prop key="country">中国</prop>
                <prop key="city">南昌</prop>
                <prop key="province">江西</prop>
            </props>
</property>

Spring重要API

ApplicationContext app = new ClasspathXmlApplicationContext("xml文件")
app.getBean("id")
app.getBean(Class)

三、案例数据源对象管理

  • 导入druid坐标、导入c3p0坐标和mysql连接坐标
    <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.10</version>
    </dependency>
    <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
 </dependency>
 <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
 </dependency>
  • 配置数据源对象作为spring管理的bean
<!--    管理DruidDataSource对象-->
    <bean id="dataSource"  class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/message"/>
        <property name="username" value="root"/>
        <property name="password" value="505489"/>
    </bean>
  • 配置数据源对象作为spring管理的bean
<!--    管理c3p0对象-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/message"/>
        <property name="user" value="root"/>
        <property name="password" value="505489"/>
    </bean>
  • 加载properties文件
  1. 首先开启命名空间
<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
">
</beans>

2.使用context空间加载properties文件

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

3.使用属性占位符${}读取properties文件中的属性

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.Driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
</bean>
  • 方式一:路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  • 方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\applicationContext.xml");
  • 方式三:读取web下的资源文件
XmlWebApplicationContext ctx = new XmlWebApplicationContext();
  • 加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml"); 

获取bean

  • 方式一:使用bean名称获取
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
  • 方式二:使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
  • 方式三:使用bean类型获取
BookDao bookDao = ctx.getBean(BookDao.class);

容器层次结构

总览 BeanFactory 体系,按照接口的抽象层次,大体可以分层四层:

  • 第一层:BeanFactory
  • 第二层:HierarchicalBeanFactoryListableBeanFactoryAutowireCapableBeanFactory
  • 第三层:ConfigurableBeanFactory,此外还有一个关联性较强SingletonBeanRegistry
  • 第四层:ConfigurableListableBeanFactory

BeanFactory初始化

  • 类路径加载配置文件
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao =  bf.getBean("bookDao",BookDao.class);
bookDao.save();

注意:BeanFactory创建完毕后,所有的bean均为延时加载

延时加载好处:当为了追求传输效率就会需要什么就再去创建什么时,就会体现出延迟加载的好处,有一个缓冲时间。

四、IOC和DI注解开发

注解开发-定义Bean

  • 使用@Component定义bean
@Component("bookDao")
public class BookDaoImpl implements BookDao{
}
@Component
public class BookServiceImpl implements BookService{
}
  • 核心配置文件中通过组件扫描加载bean
<context:component-scan base-package="com.hcx"/>
  • Spring提供@Component注解的三个衍生注解

    • @Controller:用于表现层bean定义
    • @Service:用于业务层bean定义
    • @Repository:用于数据层bean定义
@Repository("bookDao")
public class BookDaoImpl implements BookDao{
}
@Service
public class BookServiceImpl implements BookService{
}

核心配置文件替换

  • Spring 3.0 升级了纯注解开发模式,使用了Java类代替配置文件,开启了Spring快速开发赛道
  • Java类代替Spring核心配置文件,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.springframework.org/schema/beans/spring-beans.xsd">
	   <context:component-scan base-package="com.hcx"/>
</beans>

@Configuration
@ComponentScan("com.hcx")
public class SpringConfig{
}

代替

  • @Configuration注解用于设定当前类为配置类
  • @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
@ComponentScan({"com.hcx.service","com.hcx.dao"})
  • 读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
//加载配置文件初始化容器(xml版)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

自动装配

  • 使用@Autowired注解开启自动装配模式(按类型)
@Servcie
public class BookServiceImpl implements BookService{
	@Autowired
	private BookDao bookDao;
	public void setBookDao(BookDao bookDao){
	this.bookDao=bookDao;
	}
	public void save(){
	System.out.print("book service save ...");
	bookDao.save();
	}
}
  • 注意:自动装配基于反射设计创建对象并暴力反射对应属性初始化数据,因此无需提供setter()方法
  • 注意:自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法
  • 使用@Qualifier注解开启指定名称装配bean
@Service 
public class BookServiceImpl implements BookService{
	@Autowired
	@Qualifier("bookDao")
	private BookDao bookDAO;
}
  • 注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
简单数据类型注入

在定义的数据类型上放使用@Value("值")

@Value("学习")
private String action;

加载外部properties文件

  • 在SpringConfig类下,使用@PropertySource注解加载properties文件
@Configuration
@ComponentScan("com.hcx")
@uPropertySource("classpath:jdbc.properties")
public class SpringConfig{}
  • 在给属性注入值时
@Value("${外部文件中定义的属性名}")
private String value;
  • 注意:路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符

第三方Bean管理

  • 使用@Bean配置第三方bean
@Configuration
public class SpringConfig{
	@Bean
	public DataSource dataSource(){
    DruidDataSource ds = new DruidDataSource();
	ds.setDriverClassName("com.mysql.jdbc.Driver");
	ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
	ds.setUsername("root");
	ds.setPassword("root");
	return ds;
	}
}
//不推荐
  • 将独立的配置类加入核心配置
  • 方式一:导入式
public class JdbcConfig{
	@Bean
	public DataSource dataSource(){
	DruidDataSource ds = new DruidDataSource();
	//相关配置
	return ds;
	}
}
  • 使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式
@Configuration
@Import(JdbcConfig.class)
public class SpringConfig{
}

第三方Bean依赖注入

  • 简单类型依赖注入
public class JdbcConfig{
	@Value("com.mysql.jdbc.Driver")
	private String dirver;
	@Value("jdbc:mysql://localhost:3306/spring_db")
	private String url;
	@Value("root")
	private String userName;
	@Value("505489")
	private String password;
	@Bean
	public DataSource dataSource(){
		DruidDataSource ds = new DruidDatSource();
		ds.setDriverClassName(driver);
		ds.setUrl(url);
		ds.setUserName(userName);
		ds.setPassword(password);
		return ds;
	}
}
  • 引用类型依赖注入
@Bean
public DataSource dataSource(BookService bookService){
	Sytstem.out.print(bookService);
	DruidDataSource ds = new DruidDataSource();
	//属性设置
	return ds;
}
  • 引用类型注入只需要为bean定义方法设置形参即可,容器会更卷类型自动装配对象

创建Dao接口(用注解的形式)

image.png

步骤四:创建Service接口和实现类

image.png

image.png

步骤五:添加jdbc.properties配置文件

image.png

步骤六:创建SpringConfig、MybatisConfig、JdbcConfig配置类

image.png

image.png

image.png

步骤七:编写运行类

image.png

五、AOP

  • AOP(Aspect Oriented Programming)面向切面编程,是一种编程范式,指导开发者如何组织程序结构

    • OOP(Object Oriented Programming)面向对象编程
  • 作用:在步惊动原始设计的基础上进行功能增强,追加功能

  • Spring理念:无侵入式

核心概念

  • 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的
  • 代理(Proxy):目标对象无法直接工作,需要对其进行功能会填,通过原始对象的代理对象实现
  • SpringAOP本质:代理模式

image.png

连接点与切入点

  • 连接点:执行的方法,程序执行过程中的任意位置,可以为方法,抛出异常,也可以为设置变量。

  • 切入点:需要被增强的方法,一个切入点可以描述一个具体的方法,也可以匹配多个方法,一个切入点可以只匹配一个update方法,也可以匹配某个包下面所有的查询方法。

  • 【连接点范围 > 切入点范围,切入点一定是连接点,反之未必】

通知与通知类

  • 通知:存放共性功能的方法,在切入点处执行的操作,也就是共性功能。

  • 通知类:定义通知的类,通知是一个方法,方法不能独立存在,需要被写在一个类中,这个类我们也给起了个名字叫通知类

切面

  • 切面:通知与切入点之间的关系描述

通知是要增强的内容,会有多个;切入点是需要被增强的方法,也会有多个,哪个切入点需要添加哪个通知,就需要提前将它们之间的关系描述清楚,那么对于通知和切入点之间的关系描述,我们称之为切面

入门案例

  1. 导入aop相关坐标
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.4</version>
</dependency>	

说明:Spring-context坐标依赖spring-aop坐标

2.定义dao接口与实现类

public interface BookDao{
	public void save();
	public void update();
}
@Repository
public class BookDaoImpl implements BookDao{
	public void save(){
		System.out.println(System.currentTimeMills());
		System.out.println("book dao save...");
	}
	
	public void update(){
		System.out.println("book dao update...");
	}
}

3.定义通知类,制作通知

public class MyAdvice{
	public void before(){
	System.out.println(System.currentTimeMills());
	}
}

4.定义切入点

public class MyAdvice{
	@Pointcut("execution(void com.hcx.dao.BookDao.update())")
	private void pt(){}
}

说明:切入点定义依托一个不具有实际意义的方法进行,即无参数,无返回值,方法体无实际逻辑

5.绑定切入点与通知关系,并指定通知添加到原始连接点的具有执行位置

public class MyAdvice{
	@Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}
    
    @Before("pt()")
    public void before(){
        System.out.println(System.currenTimeMillis());
    }
}

6.定义通知类受Spring容器管理,并定义当前类为切面类

@Componet
@Aspect
public class MyAdvice{
	@Pointcut("execution(void com.hcx.dao.BookDao.update())")
	private void pt(){}
	@Before("pt()")
	public void before(){
		System.out.println(System.currentTimeMillis());
	}
}

7.开启Spring对AOP注解驱动支持

@Configuration
@ComponetScan("com.hcx")
@EnableAspectAutoProxy
public class SpringConfig{
}

通知类型

那么当对findName()进行增强的时候,通知类中的共性方法如何才能获取findName中的参数id呢?

使用JoinPoint 通知作如下修改:

@Before("pt()")
public void before(JoinPoint jp)
    Object[] args = jp.getArgs();
    System.out.println(Arrays.toString(args));
 
    System.out.println("before advice ..." );
}

我们在执行类执行findName(100)时,输出如下:

image.png

可见,共性方法成功得到了执行方法中的id参数,并且以数组的形式进行了输出(因为方法中的形参可能有多个)

如果执行方法为findName(id, password),在执行类执行findName(100,itheima),那么输出为:

image.png

  • @Around注意事项

    1. 环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
    2. 通知中如果为使用ProceedIngJoinPoint对原始方法进行调用将跳过原始方法的执行
    3. 对原始方法的调用可以不接收返回值,通知方法设置称void即可,如果接收返回值,必须设定为Object类型
    4. 原始方法的返回值如果是void类型,通知方法的返回值类型可以设置成void,也可以设置成Object
    5. 由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象

    **

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
    System.out.println("around before advice ...");
    Object ret = pjp.proceed();
    System.out.println("around after advice ...");
    return ret;
    }
    
    • 名称:@AfterReturning(了解)

    • 类型:方法注解

    • 位置:通知方法定义上方

    • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法正常执行完毕后运行

    • 范例:

      @AfterReturning("pt()")
      public void after Returning(){
      System.out.println("afterReturning advice ...");
      }
      
    • 相关属性:value(默认):切入点方法名,格式为类名.方法名()

    • 名称:@AfterThrowing(了解)

    • 类型:方法注解

    • 位置:通知方法定义上方

    • 作用:设置当前通知方法与切入点之间的绑定关系,当前通知方法在原始切入点方法运行抛出异常后执行

    • 范例:

    @AfterThorwing("pt()")
    public void afterThorwing(){
    	System.out.println("afterThrowing advice ...");
    }
    
  • 相关属性:value(默认):欺辱点方法名,格式为:类名.方法名()