SSM(2):spring
Spring IoC
spring Ioc 容器组件,可以完成对象的创建,对象属性赋值,对象管理
2.1 Spring框架部署(IoC)
2.1.1 创建Maven工程
-
java
-Web
2.1.2 添加SpringIoC依赖 -
core
-
beans
-
aop
-
expression
-
context
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
2.1.3创建Spring配置文件
通过配置文件“告诉”Spring容器创建什么对象,给对象赋什么值
- 在Resource目录创建 applicationContext.xml 文件(文件名也可自定义)
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--对于一个xml文件如果作为框架的配置文件,需要遵守框架的配置规则-->
<!--通常一个框架为了开发者能够正确的配置,都会提供xml的规范文件(dtd\xsd)-->
<!--xsd 可以根据配置引入多个,只要引入了相应的xsd,可以使用相应标签规则属性-->
</beans>
2.2 SpringIoC的使用
使用SpringIoC组件创建并管理对象
2.2.1 创建一个实体类
public class Student {
private String stuNum;
private String stuName;
private String stuGender;
private int stuAge;
private Date enterenceTime;//入学日期
}
2.2.2 在Spring配置文件中配置实体类
ClassPathXmlApplicationContext
//通过Spring容器创建Student对象
//1、初始化Spring容器,加载Spring配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2、通过Spring容器,获取Student对象
Student student2 = (Student) context.getBean("stu");
2.3 IoC和DI
IoC:控制反转,依赖Spring对象工厂,完成对象的创建
DI:依赖注入,在Spring完成对象创建的同时依赖Spring容器完成对象属性的赋值
2.3.1 IoC
当我们需要通过Spring对象工场创建某个类的对象是时候,需要将这个对象交给Spring管理——通过bean标签配置
<bean id="book" class="com.atguigu.ioc.bean.Book"><bean/>
2.3.2 DI
通过Spring容器给创建的对象属性赋值
<!--通过bean标签将实体类配置给Spring进行管理,id表示实体类的唯一标识(自己定义,一般是类名小写)-->
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="stuNum" value="10002"/>
<property name="stuName" value="李四"/>
<property name="stuGender" value="女"/>
<property name="stuAge" value="18"/>
<property name="enterenceTime" ref="date"/>
</bean>
2.4 DI依赖注入
2.4.1 依赖注入的三种方式:
Spring容器加载配置文件以后,通过反射创建类的对象,并给属性赋值;
Spring容器通过反射实现属性注入有三种方式:
- set方法注入
- 构造器注入
- 接口注入(不常用)
2.4.2 set方法注入
在bean标签中通过配置property标签给对象属性赋值,实际上就是通过反射调用set方法完成属性的注入
简单类型以及字符串
直接通过property标签的value属性赋值
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<!--简单类型-->
<property name="stuNum" value="10001"/>
<!--字符串类型-->
<property name="stuName" value="李四"/>
</bean>
日期对象
方式1:在property标签中通过ref引用Spring容器中的一个对象
<bean id = "date" class="java.util.Date"></bean>
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="enterenceTime" ref="date"/>
</bean>
方式2:在property标签中添加子标签bean来指定对象
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="enterenceTime">
<bean class="java.util.Date"/>
</property>
</bean>
自定义类对象属性
方式1:
<bean id="clazz" class="com.liguoqing.ioc.bean.Clazz">
<property name="classId" value="2010"/>
<property name="className" value="java2010"/>
</bean>
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="clazz" ref="clazz"/>
</bean>
方式2:
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="clazz">
<bean class="com.liguoqing.ioc.bean.Clazz">
<property name="classId" value="2010"/>
<property name="className" value="java2010"/>
</bean>
</property>
</bean>
集合类型
List
1: List List中的元素是字符串或者简单类型的封装类
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="hobbies" value="旅游,电影"/>
</bean>
--------------------或者下面这种引用方式也可以---------------------------------------
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="hobbies">
<list>
<value>旅游</value>
<value>电影</value>
<value>吃粑粑</value>
</list>
</property>
</bean>
2:List List中的元素是对象类型
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="hobbies">
<list>
<bean class="com.liguoqing.ioc.bean.Book"/>
<bean class="com.liguoqing.ioc.bean.Book"/>
<bean class="com.liguoqing.ioc.bean.Book"/>
</list>
</property>
</bean>
------------------或者下面这种引用方式也可以-----------------------------------------------------
<bean id="book" class="com.liguoqing.ioc.bean.Book"></bean>
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="hobbies">
<list>
<ref bean="book"></ref>
<ref bean="book"></ref>
<ref bean="book"></ref>
</list>
</property>
</bean>
Set
Set 略,只需要原来的list标签换成set标签
Map
键值对
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="map">
<map>
<entry>
<key>
<value>k1</value>
</key>
<value>123</value>
</entry>
<entry>
<key>
<value>k2</value>
</key>
<value>456</value>
</entry>
</map>
</property>
</bean>
Properties
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<property name="properties">
<props>
<prop key="key1">aaa</prop>
<prop key="key2">aaa</prop>
</props>
</property>
</bean>
2.4.3 构造器注入
参数顺序需要注意(顺序不与构造器同,以index=" " 索引)
简单类型、字符串、对象
public class Student {
private String stuNum;
private String stuName;
private String stuGender;
private int stuAge;
private Date date;
private Clazz clazz;
public Student(String stuNum, String stuName, String stuGender, int stuAge, Date date, Clazz clazz) {
this.stuNum = stuNum;
this.stuName = stuName;
this.stuGender = stuGender;
this.stuAge = stuAge;
this.date = date;
this.clazz = clazz;
}
}
--------------------------------------------------
<bean id="data" class="java.util.Date"></bean>
<bean id="stu" class="com.liguoqing.ioc.bean.Student">
<constructor-arg index="0" value="10001"/> <!--字符串类型-->
<constructor-arg value="张三"/>
<constructor-arg value="女"/>
<constructor-arg value="21"/> <!--简单类型-->
<constructor-arg ref="data"/> <!--对象类型-->
<constructor-arg >
<bean class="com.liguoqing.ioc.bean.Clazz"></bean>
</constructor-arg> <!--自定义类对象类型-->
</bean>
集合类型属性
public class Student {
private List<String> hobbies;
private Set<String> sets;
private Map<String,Object> maps;
private Properties properties;
public Student(List<String> hobbies, Set<String> sets, Map<String, Object> maps, Properties properties) {
this.hobbies = hobbies;
this.sets = sets;
this.maps = maps;
this.properties = properties;
}
}
-----------------------------------------------------------------------------------------------
<bean id="stu2" class="com.liguoqing.ioc.bean.Student">
<constructor-arg index="0">
<list>
<value>11</value>
<value>13</value>
<value>12</value>
</list>
</constructor-arg>
<constructor-arg index="1">
<set>
<value>11</value>
<value>13</value>
<value>12</value>
</set>
</constructor-arg>
<constructor-arg index="2">
<map>
<entry>
<key><value>1</value></key>
<value>value</value>
</entry>
<entry>
<key><value>2</value></key>
<value>value2</value>
</entry>
</map>
</constructor-arg>
<constructor-arg index="3">
<props>
<prop key="k1">value1</prop>
<prop key="k2">value2</prop>
</props>
</constructor-arg>
</bean>
2.5 Bean的作用域
在Bean标签中可以通过scope属性来知道对象的作用域
scope=“singleton” 表示 当前bean 是单例模式(默认是饿汉模式;Spring容器初始化阶段就会完成此对象的创建;当在bean标签设置 lazy-init="true" 则变为懒汉模式)
scope=“prototype” 表示 当前bean 是非单例模式,每次通过Spring容器获取此bean的对象时都会创建一个新的对象
单例
<bean id="stu" class="com.atguigu.ioc.bean.Student" scope="singleton" lazy-iniy="true"></bean>
多例
<bean id="stu" class="com.atguigu.ioc.bean.Student" scope="prototype" lazy-iniy="true"></bean>
2.6 Bean的生命周期方法
在bean标签中可以通过 init-method 属性指定当前bean的初始化方法,初始化方法在构造器执行之后执行
在bean标签中可以通过 destroy-method 属性指定当前bean的销毁方法,销毁方法在对象销毁之前执行
Bean
package com.liguoqing.ioc.bean;
public class Book {
private int bookId;
private String bookName;
//初始化方法:在创建当前类对象时调用的方法,进行一些资源准备工作
public void init(){
System.out.println("__________________init");
this.bookId = 1;
this.bookName = "初始值";
}
//销毁方法:在Spring容器销毁对象时调用此方法,进行一些资源回收性的操作
public void destory(){
System.out.println("__________destory");
}
在Spring的配置文件:
<bean id="stu" class="com.atguigu.ioc.bean.Student" scope="prototype" lazy-iniy="true" init-method="init" destroy-meth="destroy"></bean>
2.7 自动装配
自动装配:Spring在实例化当前bean的时候从Spring容器中找到匹配的实例赋值给当前bean的属性
autowire=“byName” 根据当前Bean的属性名,在Spring容器中寻找匹配的对象,如果根据Name找到了bean,但是类型不匹配则会抛出异常。
autowire=“byType” 根据当前Bean的属性类型,在spring容器中寻找匹配的对象,如果根据类型找打了多个类型匹配的bean,也会抛出异常
<bean id="clazz" class="com.atguigu.ioc.bean.Clazz"></bean>
<bean id="clazz2" class="com.atguigu.ioc.bean.Clazz"></bean>
<bean id="stu3" class="com.atguigu.ioc.bean.Student" autowire="byName"></bean> <!--clazz 此时该name的bean需要唯一-->
<bean id="stu3" class="com.atguigu.ioc.bean.Student" autowire="byType"></bean> <!--clazz2 此时该类型的bean需要唯一-->
2.8 SpringIoC 工作原理

三、SpringIoC——基于注解
SpringIoC的使用,需要我们通过XML将类声明给Spring容器进行管理,从而通过Spring工厂完成对象的创建及属性值的注入;
Spring除了提供基于XML的配置方式,同时提供了基于注解的配置;直接在实体类中添加注解声明Spring容器管理,以简化开发步骤。
3.1 SpringIoC框架部署
3.1.1 创建Maven项目
3.1.2 添加SpringIoC依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
3.1.3 创建Spring配置文件
因为Spring容器初始化时,只会加载applicationContext.xml 文件,那么我们在实体类中添加注解就不会被Spring扫描,所有我们需要在applicationContext.xml中声明Spring的扫描范围,以达到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"
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">
<!-- 声明使用注解配置-->
<context:annotation-config/>
<!-- 声明Spring工厂注解的扫描范围-->
<context:component-scan base-package=""/>
</beans>
3.2 IoC常用注解
3.2.1 @Component(“stu”)
- 类的注解,声明此类被Spring容器进行管理,相当于bean标签的作用
- @Component(value=“类的别名”)
value属性用于制定当前bean的id属性,或者叫别名。value属性也可以省略,如果省略,那么当前类的id默认为当前类名首字母改小写 - @Service、@Controller、@Repository这三个注解也可以将类声明给Spring管理,他们主要是语义上的区别
- @Controller注解主要声明将控制器类配置给Spring管理,例如Servlet
- @Service注解主要声明业务处理类配置给Spring管理,Service接口的实现类
- @Repository注解主要声明持久化类配置给Spring管理,DAO接口
- @Component除了控制器,Service,DAO之外的类一律使用此注解声明
3.2.2 @Scope(value = “prototype”)
- 类注解,用于声明当前类单例模式还是非单例模式,相当于bean标签的scope属性
- @Scope(“propotype”)表示当前类为非单例模式(默认单例模式)
3.2.3 @Lazy
- 类注解,用于声明一个单例模式的bean是否为懒汉模式
- @Lazy(true) 表示声明为懒汉模式,默认为饿汉模式
3.2.4 @PostConstruct
方法注解,声明一个方法为当前类的初始化方法(在构造器之后执行),相当于bean标签的init-method属性
3.2.5 @PreDestroy
方法注解,声明一个方法为当前类的销毁方法(在对象从容器中释放之前执行),相当于bean标签的destory-method属性
3.2.6 @Autowired
属性注解、方法注解(set)声明当前属性自动装配,默认byType,默认必须(如果没有找到类型与属性类型匹配的bean则抛出异常)
@Autowired(required = false) 通过required属性设置当前自动装配是否为必须(默认必须——如果没有找到类型与属性类型匹配的bean则抛出异常)
- byType
- ref引用
- @Qualifier(“a”) 通过id
@Autowired(required = false)
public void setClazz(@Qualifier("a") Clazz clazz) {
this.clazz = clazz;
}
3.2.7 @Resource
属性注解,也用于声明属性自动装配
默认装配方式为byName,如果根据byName没有找到相应的bean,则继续根据byType寻找对应的bean,根据byType如果没找到bean,或者找到不止一个类型匹配的bean则抛出异常。
四、代理设计模式
4.1 生活中的代理

代理设计模式的优点:将通用性的工作交由代理对象完成,被代理对象只需专注于自己的核心业务
4.2 静态代理
静态代理:代理类只能为特定的类生产代理对象,不能代理任意类

使用代理的好处:
- 被代理类中只用关注核心业务的实现,将通用的管理型逻辑(事务管理、日志管理)和业务逻辑分离
- 将通用的代码放在代理类中实现,提高了代码的复用性
- 通过在代理类添加业务逻辑,实现对原有业务逻辑扩展(增强)
4.3 动态代理
动态代理:几乎可以为所有的类产生代理对象
动态代理的实现方式有两种:
- JDK动态代理
- CGLib动态代理
4.3.1 JDK动态代理
package com.liguoqing.dao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理:是通过被代理对象实现的接口产生其代理对象
* 1:创建一个类,实现InvocationHandler接口,重写invoke方法
* 2:在类中定义一个Object类型的变量,用于传递被代理对象,并提供这个变量的有参构造器,用于将被代理对象传递进来
* 3:创建getProxy方法,用于创建并返回代理对象
* */
public class JDKMyDynamicProxy implements InvocationHandler {
//被代理对象
private Object obj;
public JDKMyDynamicProxy(Object obj) {
this.obj = obj;
}
//产生代理对象,返回代理对象
public Object getProxy(){
//1、获取被代理对象的类加载器
ClassLoader classLoader = obj.getClass().getClassLoader();
//2、获取被代理对象的类所实现的接口
Class<?>[] interfaces = obj.getClass().getInterfaces();
//3、产生代理对象(通过被代理对象的类加载器及实现的接口)
//第一个参数:被代理对象的类加载器
//第二个参数:被代理对象实现的接口
//第三个参数:使用产生的代理对象调用方法时,用于拦截方法执行的处理器
Object proxy = Proxy.newProxyInstance(classLoader, interfaces,this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
begin();
Object returnValue = method.invoke(obj,args);//执行method方法(入参)
commit();
return returnValue;
}
public void begin(){
System.out.println("~~~~~~~开启事务");
}
public void commit(){
System.out.println("~~~~~~~提交事务");
}
}
----------------------------------------------------------------
测试类:
package com.liguoqing.test;
import com.liguoqing.dao.BookDAOImpl;
import com.liguoqing.dao.GenaralDAO;
import com.liguoqing.dao.JDKMyDynamicProxy;
import com.liguoqing.dao.StudentDAOImpl;
public class TestDynamicProxy {
public static void main(String[] args) {
//被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//创建动态代理类对象,并将被代理对象传递到代理类中,赋值给obj
JDKMyDynamicProxy jdkMyDynamicProxy = new JDKMyDynamicProxy(studentDAO);
//proxy就是产生的代理对象,产生的代理对象可以强转成被代理对象实现的接口类型
GenaralDAO proxy = (GenaralDAO) jdkMyDynamicProxy.getProxy();
//使用代理对象调用方法,并不会执行调用的方法,而是进入到创建代理对象时指定的InvocationHandler类中的invoke方法
//调用的方法作为一个Method参数,传递给了invoke方法
proxy.delete();
}
}
4.3.2 CGLib动态代理
由于JDK动态代理时通过被代理类实现的接口来创建代理对象的,因此JDK动态代理只能代理实现了接口的类对象。如果一个类没有实现任何接口,该如何产生代理对象呢?——CGLib动态代理
CGLib动态代理,是通过创建被代理类的子类来创建代理对象的,因此即使没有实现任何接口的类也可以通过CGLib产生代理对象
CGLib动态代理不能为final修饰的类创建代理对象
添加CGLib的依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
CGLib动态代理代码实现
package com.liguoqing.dao;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 1:添加cglib依赖
* 2:创建一个类,实现MethodInterceptor接口,同时实现接口中的intercept方法
* 3:在类中定义一个Object类型的变量,并提供这个变量的有参构造器,用于传递被代理对象
* 4:定义getProxy方法创建并返回代理对象(代理对象是通过创建被代理类的子类来创建的)
* */
public class CGLibDynamicProxy implements MethodInterceptor {
private Object obj;
public CGLibDynamicProxy(Object obj) {
this.obj = obj;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxy = enhancer.create();
return proxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
begin();
Object returnValue = method.invoke(obj,objects);//通过反射调用被代理类的方法
commit();
return returnValue;
}
public void begin(){
System.out.println("~~~~~~~开启事务");
}
public void commit(){
System.out.println("~~~~~~~提交事务");
}
}
------------------------------------------------------------------------------------
测试类:
package com.liguoqing.test;
import com.liguoqing.dao.*;
public class TestDynamicProxy {
public static void main(String[] args) {
//创建被代理对象
BookDAOImpl bookDAO = new BookDAOImpl();
StudentDAOImpl studentDAO = new StudentDAOImpl();
//通过cglib动态代理类创建代理对象
CGLibDynamicProxy cgLibDynamicProxy = new CGLibDynamicProxy(bookDAO);
//代理对象实际上是被代理对象子类,因此代理对象可以直接强转为被代理类类型
BookDAOImpl proxy = (BookDAOImpl)cgLibDynamicProxy.getProxy();
//使用代理对象调用方法,实际上并没有执行这个方法,而是执行了代理类中的intercept方法,将当前调用的方法以及方法中的参数
//传递到intercept方法
proxy.update();
}
}
五、SpringAOP
5.1 AOP 概念
Aspect Oriented Programming 面向切面编程,是一种利用"横切"的技术(底层实现就是动态代理),对原有的业务逻辑进行拦截,并且可以在这个拦截的横切面上添加特定的业务逻辑,对原有的业务进行增强。
———
基于动态代理,实现在不改变原有业务的情况下对业务逻辑进行增强

5.2 SpringAOP框架部署
5.2.1 创建Maven项目
5.2.2 添加依赖
- context
- aspects
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.12.RELEASE</version>
</dependency>
5.2.3 创建Spring配置文件
- 需要引入aop的命名空间
<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">
</beans>
5.3 AOP配置——基于XML
在DAO的方法前后添加开启事务和提交事务的逻辑
5.3.1 创建一个类,定义要添加的业务逻辑
public class TxManager {
public void begin(){
System.out.println("______开启事务");
}
public void commit(){
System.out.println("______提交事务");
}
}
5.3.2 配置AOP
<?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="bookDAO" class="com.liguoqing.dao.BookDAOImpl"></bean>
<bean id="studentDAO" class="com.liguoqing.dao.StudentDAOImpl"></bean>
<bean id="txManager" class="com.liguoqing.utils.TxManager"></bean>
<aop:config>
<!-- 声明切入点-->
<aop:pointcut id="book_all" expression="execution(* com.liguoqing.dao.*.*(..))"/>
<!-- 声明txManager为切面类-->
<aop:aspect ref="txManager">
<!-- 通知-->
<aop:before method="begin" pointcut-ref="book_all"/>
<aop:after method="commit" pointcut-ref="book_all"/>
</aop:aspect>
</aop:config>
</beans>
AOP开发步骤:
- 创建切面类,在切面类定义切面方法
- 将切面类配置给Spring容器
- 声明切入点
- 配置AOP通知策略
5.4 切入点的声明
5.4.1 各种切入点声明方式
<!-- 使用aop:pointcut声明切入点;切入点可以是一个方法,-->
<aop:pointcut id="book-insert" expression="execution(* com.liguoqing.dao.BookDAOImpl.insert())"/>
<!-- BookDAOImpl类中所有无参数无返回值的方法-->
<aop:pointcut id="book_pc1" expression="execution(void com.liguoqing.dao.BookDAOImpl.*())"/>
<!-- BookDAOImpl类中所有无返回值的方法(对参数无要求)-->
<aop:pointcut id="book_pc2" expression="execution(void com.liguoqing.dao.BookDAOImpl.*(..))"/>
<!-- BookDAOImpl类中所有无参数的方法(对返回值无要求)-->
<aop:pointcut id="book_pc3" expression="execution(* com.liguoqing.dao.BookDAOImpl.*())"/>
<!-- BookDAOImpl类中所有的方法(对参数、返回值都无要求)-->
<aop:pointcut id="book_pc4" expression="execution(* com.liguoqing.dao.BookDAOImpl.*(..))"/>
<!-- dao包中所有类中的所有方法(对参数、返回值都无要求)-->
<aop:pointcut id="pc5" expression="execution(* com.liguoqing.dao.*.*(..))"/>
<!-- dao包中所有类中的insert方法(对参数、返回值都无要求)-->
<aop:pointcut id="pc6" expression="execution(* com.liguoqing.dao.*.insert(..))"/>
<!-- -->
<aop:pointcut id="pc7" expression="execution(* *(..))"/>
5.4.2 AOP使用注意事项
//如果要使用Spring aop面向切面编程,***调用切入点方法的对象必须通过Spring容器获取***
//如果一个类中的方法被声明为切入点并织入了切点之后,通过Spring容器获取该类对象,实则获取到的是一个代理对象,
//如果一个类中的方法没有被声明为切入点,通过Spring容器获取的就是这个类真是创建的对象
// BookServiceDAOImpl bookServiceDAO = new BookServiceDAOImpl();
BookServiceDAOImpl bookServiceDAO = (BookServiceDAOImpl) context.getBean("bookService");
bookServiceDAO.addBook();
5.5 AOP通知策略
AOP通知策略:就是声明将切面类中的切点方法如何织入到切入点
- before
- after
- after-throwing
- after-returning
- around
5.5.1 定义切面类
package com.liguoqing.utils;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAspect {
public void method1(){
System.out.println("~~~~~~~~~~~~~method1");
}
public void method2(){
System.out.println("~~~~~~~~~~~~~method2");
}
public void method3(){
System.out.println("~~~~~~~~~~~~~method3");
}
public void method4(){
System.out.println("~~~~~~~~~~~~~method4");
}
//环绕通知的方法,必须遵守如下的定义规则
//1:必须带有一个ProceedingJoinPoint类型的参数,
//2:必须有Object类型的返回值
//3:在前后增强的业务逻辑之间执行Object v = point.proceed();
//4: 方法最后返回 return v;
public Object method5(ProceedingJoinPoint point) throws Throwable {
System.out.println("~~~~~~~~~~~~~method5----before");
//此句代码的执行就表示切入点方法的执行
Object v = point.proceed();
System.out.println("~~~~~~~~~~~~~method5----after");
return v;
}
}
5.5.2 配置切面类
<?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="myAspect" class="com.liguoqing.utils.MyAspect"></bean>
<aop:config>
<!-- 使用aop:pointcut声明切入点;切入点可以是一个方法,-->
<aop:pointcut id="book-insert" expression="execution(* com.liguoqing.dao.BookDAOImpl.insert())"/>
<aop:aspect ref="myAspect">
<!-- aop:before 前置通知,切入到指定切入点之前-->
<aop:before method="method1" pointcut-ref="book-insert"/>
<!-- aop:after 后置通知,切入到指定切入点之后-->
<aop:after method="method2" pointcut-ref="book-insert"/>
<!-- aop:after-throwing 异常通知,切入点抛出异常之后-->
<aop:after-throwing method="method3" pointcut-ref="book-insert"/>
<!-- aop:after-returning 方法返回值返回之后,对于一个java方法而言return返回值也是方法的一部分
因此”方法返回值返回之后“和”方法执行结束“是同一个时间点,所以after和after-returning根据配置的顺序决定执行的顺序-->
<aop:after-returning method="method4" pointcut-ref="book-insert"/>
<!-- aop:around 环绕通知,-->
<aop:around method="method5" pointcut-ref="book-insert"/>
</aop:aspect>
</aop:config>
</beans>
六、SpringAOP注解配置
6.1 Spring AOP注解配置框架部署
6.1.1 创建Maven工程
6.1.2 添加Spring依赖
- context
- aspects
6.1.3 Spring配置文件
<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:annotation-config/>
<context:component-scan base-package="com.liguoqing"/>
<!--基于注解配置的AOP代理-->
<aop:aspectj-autoproxy/>
</beans>
6.2 AOP注解配置案例
package com.liguoqing.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class TransactionManager {
@Pointcut("execution(* com.liguoqing.dao.*.*(..))") //定义切入点
public void pc1(){
}
@Before("pc1()")
public void begin(){
System.out.println("~~~开启事务");
}
@After("pc1()")
public void commit(){
System.out.println("~~~提交事务");
}
@Around("pc1()")
public Object printExecuteTime(ProceedingJoinPoint point) throws Throwable {
long time1 = System.currentTimeMillis();
Object v = point.proceed();
long time2 = System.currentTimeMillis();
System.out.println("~~~time:" + (time2 - time1));
return v;
}
}
注意:注解使用虽然方便,但是只能在源码上添加注解,因此我们的自定义类提倡使用注解配置,但是如果使用到第三方提供的类则需要通过XML配置形式完成配置。
七、Spring整合MyBatis
Spring两大核心思想:IoC和AOP
IoC:控制反转,Spring容器可以完成对象的创建、属性注入、对象管理等工作
AOP:面向切面,在不修改原有业务逻辑的情况下,实现原有业务的增强

2988

被折叠的 条评论
为什么被折叠?



