Spring5
代码以及配套资料下载地址 点我,密码 ==> long
本章内容介绍
- Spring 框架概述
- IOC 容器
- IOC 底层原理
- IOC 接口(BeanFactory)
- IOC 操作 Bean 管理(基于 xml)
- IOC 操作 Bean 管理(基于注解)
 
- Aop
- JdbcTemplate
- 事务管理
- Spring5 新特性
Spring5框架概述
- Spring 是轻量级的开源的 JavaEE 框架
- Spring 可以解决企业应用开发的复杂性
- Spring 有两个核心部分:IOC 和 Aop
- IOC:控制反转,把创建对象过程交给 Spring 进行管理
- Aop:面向切面,不修改源代码进行功能增强
 
- Spring 特点
- 方便解耦,简化开发
- Aop 编程支持
- 方便程序测试
- 方便和其他框架进行整合(Junit,MyBatis…..)
- 方便进行事务操作
- 降低 API 开发难度
 
Spring5入门案例
- IDE:IDEA 2021.3
- JDK:jdk8+
- 构建工具:Maven(目前可有可无)
- 数据库版本:8.0.28
- Spring版本:5.3.9
下载Spring5的jar包
下载地址:repo.spring.io
不想下载的可以来这里下载:


创建一个普通Java工程
导入相关jar包


创建一个User类
| 12
 3
 4
 5
 6
 7
 
 | package com.along;
 public class User {
 public void add() {
 System.out.println("Add.....");
 }
 }
 
 | 
创建 Spring 配置文件,在配置文件配置创建的对象
在src目录下创建bean1.xml
| 12
 3
 4
 5
 6
 7
 
 | <?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="user" class="com.along.User"/>
 </beans>
 
 | 
进行测试代码编写
使用Junit框架进行测试
创建一个测试包 test
创建TestSpring.java文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public class TestSpring5 {@Test
 public void testAdd(){
 
 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
 
 User user = context.getBean("user", User.class);
 System.out.println(user);
 user.add();
 }
 }
 
 | 
运行代码 –> 结果:
com.along.User@8646db9
Add…..
Spring IOC
IOC(概念和原理)
- 什么是IOC
- 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
- 使用IOC的目的:为了耦合度降低
- 入门案例就是IOC实现
 
- IOC底层原理
- 图示讲解


IOC(BeanFactory 接口)
 * 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
- ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
      *  加载配置文件时候就会把在配置文件对象进行创建
ApplicationContext实现类的区别:
| 12
 
 | new FileSystemXmlApplicationContext("c:/xxx.xml") new ClassPathXmlApplicationContext("xxx.xml")
 
 | 
IOC操作Bean管理(概念)
IOC操作Bean管理(XML方式)
创建对象
- 在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
- 在 bean 标签有很多属性,介绍常用的属性
- id 属性:唯一标识
- class 属性:类全路径(包类路径)
 
- 创建对象时候,默认也是执行无参数构造方法完成对象创建
| 12
 
 | <bean id="user" class="com.along.User"/>
 
 | 
注入属性
IOC和DI的区别:DI是IOC的一种具体实现,标识依赖注入或是注入属性,但是注入属性需要在对象创建完成之后执行
使用set方法进行注入
(1) 创建类,定义属性和对应的set方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | package com.along;
 public class Book {
 
 private String bname;
 private String bauthor;
 
 
 public void setBname(String bname) {
 this.bname = bname;
 }
 
 public void setBauthor(String bauthor) {
 this.bauthor = bauthor;
 }
 
 @Override
 public String toString() {
 return "Book{" +
 "bname='" + bname + '\'' +
 ", bauthor='" + bauthor + '\'' +
 '}';
 }
 }
 
 | 
(2) 在spring配置文件中配置对象创建,配置属性注入
| 12
 3
 4
 5
 
 | <bean id="bool" class="com.along.Book">
 <property name="bname" value="葵花宝典"/>
 <property name="bauthor" value="廖廖酱"/>
 </bean>
 
 | 
(3) 测试
| 12
 3
 4
 5
 6
 7
 8
 
 | @Testpublic void testBook(){
 
 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
 
 Book book = context.getBean("book", Book.class);
 System.out.println(book);
 }
 
 | 
使用有参构造器进行注入
(1)创建类,定义属性,创建属性对应有参数构造方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | package com.along;
 public class Orders {
 
 private String oname;
 private String address;
 
 
 public Orders(String oname, String address) {
 this.oname = oname;
 this.address = address;
 }
 
 @Override
 public String toString() {
 return "Orders{" +
 "oname='" + oname + '\'' +
 ", address='" + address + '\'' +
 '}';
 }
 }
 
 | 
在Spring配置文件中进行配置
| 12
 3
 4
 
 | <bean id="orders" class="com.along.Orders"><constructor-arg name="oname" value="电脑" />
 <constructor-arg name="address" value="China"/>
 </bean>
 
 | 
(3) 测试
| 12
 3
 4
 5
 6
 7
 8
 
 | @Testpublic void testOrder(){
 
 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
 
 Orders orders = context.getBean("orders", Orders.class);
 System.out.println(orders);
 }
 
 | 
p名称空间注入(了解)
使用 p 名称空间注入,可以简化基于 xml 配置方式
(1) 添加 p 名称空间在配置文件中 xmlns:p
| 12
 3
 4
 5
 
 | <?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:p="http://www.springframework.org/schema/p" <!-- 这里(复制记得删除这里的注释) -->
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 | 
(2) 进行属性注入,在bean中进行操作
| 1
 | <bean id="bookp" class="com.along.Book" p:bname="九阴真经" p:bauthor="廖廖"></bean>
 | 
(3) 测试
| 12
 3
 4
 5
 6
 7
 8
 
 | @Testpublic void testBookP(){
 
 ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
 
 Book book = context.getBean("bookp", Book.class);
 System.out.println(book);
 }
 
 | 
注入空值和其他类型属性
注入空值
| 12
 3
 
 | <property name="address"><null/>
 </property>
 
 | 
属性值包含特殊符号,比如 <廖狗>
(1) 把<>进行转义 <>
(2) 把带特殊符号内容写到 CDATA
| 12
 3
 
 | <property name="address"><value><![CDATA[<<南京>>]]></value>
 </property>
 
 | 
注入外部Bean
创建dao层以及实现类
| 12
 3
 4
 5
 6
 7
 
 | package com.along.dao;
 public class UserDao {
 public String getMessage(){
 return "UserDao调用数据库....";
 }
 }
 
 | 
创建service层以及实现类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | package com.along.service;
 import com.along.dao.UserDao;
 
 public class UserService {
 private UserDao userDao;
 
 public void setUserDao(UserDao userDao) {
 this.userDao = userDao;
 }
 
 public void getMsg(){
 System.out.println("service getMsg()....");
 System.out.println(userDao.getMessage());
 }
 }
 
 | 
xml文件注入
| 12
 3
 4
 5
 6
 
 | <bean id="userDaoImpl" class="com.along.dao.UserDao"></bean>
 
 <bean id="userService" class="com.along.service.UserService">
 <property name="userDao" ref="userDaoImpl"/>
 </bean>
 
 | 
测试
| 12
 3
 4
 5
 6
 
 | @Testpublic void testUserService(){
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
 UserService userService = applicationContext.getBean("userService", UserService.class);
 userService.getMsg();
 }
 
 | 
结果:
service getMsg()….
UserDao调用数据库….
注入内部Bean
一对多关系:部门和员工
一个部门有多个员工,一个员工属于一个部门
部门是一,员工是多
在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
创建实体类
部门类 员工.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | package com.along;
 public class Emp {
 private String ename;
 private String gender;
 
 private Dept dept;
 
 
 public Dept getDept() {
 return dept;
 }
 
 public void setDept(Dept dept) {
 this.dept = dept;
 }
 
 public void setEname(String ename) {
 this.ename = ename;
 }
 
 public void setGender(String gender) {
 this.gender = gender;
 }
 
 @Override
 public String toString() {
 return "Emp{" +
 "ename='" + ename + '\'' +
 ", gender='" + gender + '\'' +
 ", dept=" + dept +
 '}';
 }
 }
 
 | 
部门 Dept.java
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | package com.along;
 public class Dept {
 private String dname;
 
 public void setDname(String dname) {
 this.dname = dname;
 }
 
 @Override
 public String toString() {
 return "Dept{" +
 "dname='" + dname + '\'' +
 '}';
 }
 }
 
 | 
xml文件注入
新建一个xml文件,叫bean-emp.xml
第一种方式注入
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | <bean id="empA" class="com.along.Emp">
 
 <property name="ename" value="廖廖酱"/>
 <property name="gender" value="男"/>
 
 <property name="dept" ref="deptA"/>
 </bean>
 <bean id="deptA" class="com.along.Dept">
 <property name="dname" value="扫黄部门"/>
 </bean>
 
 | 
第二种方式注入
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | <bean id="empB" class="com.along.Emp">
 
 <property name="ename" value="杰哥"/>
 <property name="gender" value="男"/>
 
 <property name="dept" ref="deptB"/>
 <property name="dept.dname" value="打非部门"/>
 </bean>
 <bean id="deptB" class="com.along.Dept">
 <property name="dname">
 <null/>
 </property>
 </bean>
 
 | 
注入集合类型
创建类,定义数组、list、map、set 类型属性,生成对应 set 方法
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 
 | package com.along;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 public class Stu {
 
 private String[] courses;
 
 private List<String> list;
 
 public void setCourses(String[] courses) {
 this.courses = courses;
 }
 
 public void setList(List<String> list) {
 this.list = list;
 }
 
 public void setMaps(Map<String, String> maps) {
 this.maps = maps;
 }
 
 public void setSets(Set<String> sets) {
 this.sets = sets;
 }
 
 
 private Map<String, String> maps;
 
 private Set<String> sets;
 
 @Override
 public String toString() {
 return "Stu{" +
 "courses=" + Arrays.toString(courses) +
 ", list=" + list +
 ", maps=" + maps +
 ", sets=" + sets +
 '}';
 }
 }
 
 
 | 
在spring配置文件进行配置
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 
 | <bean id="stu" class="com.along.Stu">
 <property name="courses">
 <array>
 <value>廖廖酱</value>
 <value>杰哥</value>
 </array>
 </property>
 
 <property name="list">
 <list>
 <value>廖廖酱</value>
 <value>杰哥</value>
 </list>
 </property>
 
 <property name="maps">
 <map>
 <entry key="JAVA" value="java"/>
 <entry key="PYTHON" value="python"/>
 <entry key="NODE" value="node"/>
 </map>
 </property>
 
 <property name="sets">
 <set>
 <value>MYSQL</value>
 <value>MongoDB</value>
 <value>Redis</value>
 </set>
 </property>
 </bean>
 
 | 
测试
| 12
 3
 4
 5
 6
 
 | @Testpublic void testStu(){
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-stu.xml");
 Stu stu = applicationContext.getBean("stu", Stu.class);
 System.out.println(stu);
 }
 
 | 
结果:
Stu{
courses=[廖廖酱, 杰哥], 
list=[廖廖酱, 杰哥],
 maps={JAVA=java, PYTHON=python, NODE=node}, 
sets=[MYSQL, MongoDB, Redis]
}
在集合里面设置对象类型值
创建多个Book对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | <bean id="bookA" class="com.along.Book">
 <property name="bname" value="葵花宝典A"/>
 <property name="bauthor" value="廖廖酱A"/>
 </bean>
 <bean id="bookB" class="com.along.Book">
 
 <property name="bname" value="葵花宝典B"/>
 <property name="bauthor" value="廖廖酱B"/>
 </bean>
 
 | 
注入list集合类型
| 12
 3
 4
 5
 6
 
 | <property name="bookList"><list>
 <ref bean="bookA"></ref>
 <ref bean="bookB"></ref>
 </list>
 </property>
 
 | 
使用util标签完成list集合注入提取
建议创建一个新的 Java项目,和刚开始的步骤一样
建议创建一个新的 Java项目,和刚开始的步骤一样
spring 配置文件中引入名称空间 util
xmlns:util
| 12
 3
 4
 5
 6
 7
 8
 
 | <?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:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util.xsd">
 
 </beans>
 
 | 
添加Book类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | package com.along.connection;
 import java.util.List;
 
 public class Book {
 List<String> bookNameList;
 
 public void setBookNameList(List<String> bookNameList) {
 this.bookNameList = bookNameList;
 }
 
 @Override
 public String toString() {
 return "Book{" +
 "bookNameList=" + bookNameList +
 '}';
 }
 }
 
 | 
编写xml文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | <util:list id="bookList">
 <value>易筋经</value>
 <value>九阴真经</value>
 <value>九阳神功</value>
 </util:list>
 
 <bean id="book" class="com.along.connection.Book">
 <property name="bookNameList" ref="bookList"/>
 </bean>
 
 | 
测试
| 12
 3
 4
 5
 6
 
 | @Testpublic void testBook() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-book.xml");
 Book book = applicationContext.getBean("book", Book.class);
 System.out.println(book);
 }
 
 | 
结果:
Book{
bookNameList=[易筋经, 九阴真经, 九阳神功]
}
IOC 操作Bean管理(FactoryBean)
- Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
- 普通 bean:在配置文件中定义 bean 类型就是返回类型
- 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
 
实现方式:
(1) 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
(2) 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
创建类
User类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | package com.along.bean;
 public class User {
 private String name;
 
 public void setName(String name) {
 this.name = name;
 }
 
 @Override
 public String toString() {
 return "User{" +
 "name='" + name + '\'' +
 '}';
 }
 }
 
 | 
MyBean类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | package com.along.factory;
 import com.along.bean.User;
 import org.springframework.beans.factory.FactoryBean;
 
 public class MyBean implements FactoryBean<User> {
 
 
 @Override
 public User getObject() throws Exception {
 User user = new User();
 user.setName("廖狗");
 return user;
 }
 
 @Override
 public Class<?> getObjectType() {
 return null;
 }
 
 @Override
 public boolean isSingleton() {
 return FactoryBean.super.isSingleton();
 }
 }
 
 | 
测试代码
| 12
 3
 4
 5
 6
 
 | @Testpublic void testMyBean() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-factory.xml");
 User user = applicationContext.getBean("myBean", User.class);
 System.out.println(user);
 }
 
 | 
Bean的作用域
Spring中,设置创建bean实例是单实例还是多实例
默认情况下,bean 是单实例对象
| 12
 3
 4
 5
 6
 7
 8
 
 | @Testpublic void testBook() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-book.xml");
 Book bookA = applicationContext.getBean("book", Book.class);
 Book bookB = applicationContext.getBean("book", Book.class);
 System.out.println(bookA.hashCode());
 System.out.println(bookB.hashCode());
 }
 
 | 

设置单实例还是多实例
- 在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
- scope 属性值
- 默认值,singleton,表示是单实例对象
- prototype,表示是多实例对象
 
在bean xml文件中设置
| 12
 3
 4
 5
 
 |    
 <bean id="book" class="com.along.connection.Book" scope="prototype">
 <property name="bookNameList" ref="bookList"/>
 </bean>
 
 | 
再次测试:

Bean的生命周期
完整生命周期(7步)
- 通过构造器创建 bean 实例(无参数构造)
- 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
- 调用 bean 的初始化的方法(需要进行配置初始化的方法)
- 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
- bean 可以使用了(对象获取到了)
- 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
演示生命周期
创建Orders类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | public class Orders {private String oname;
 
 
 public Orders() {
 System.out.println("1.执行无参构造器");
 }
 
 public String getOname() {
 return oname;
 }
 
 public void setOname(String oname) {
 this.oname = oname;
 System.out.println("2.调用set方法设置属性值");
 }
 
 
 public void initMethod() {
 System.out.println("4.执行初始化方法");
 }
 
 
 public void destoryMethod(){
 System.out.println("7.执行销毁的方法");
 }
 }
 
 | 
添加后置处理器
创建MyBeanPost类,实现BeanPostProcessor接口,创建后置处理器
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | public class MyBeanPost implements BeanPostProcessor {@Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("3.后置处理器 postProcessBeforeInitialization");
 return bean;
 }
 
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 System.out.println("5.后置处理器 postProcessAfterInitialization");
 return bean;
 }
 }
 
 | 
测试代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | @Testpublic void testOrders() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-orders.xml");
 Orders orders = applicationContext.getBean("orders", Orders.class);
 System.out.println("4.获取到对象");
 System.out.println(orders.getOname());
 
 
 
 ((ClassPathXmlApplicationContext) applicationContext).close();
 
 }
 
 | 

XML自动装配
什么是自动装配
- 根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
实现自动装配
- 在Bean标签中有一个autowire的属性,属性中有两个值
- byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
- byType 根据属性类型注入
 
XML注入方式普遍用的不多,推荐使用注解方式
演示
本次还是使用Emp员工 与 Dept部门进行演示
创建Dept部门类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | public class Dept {private final String dname = "部门";
 
 @Override
 public String toString() {
 return "Dept{" +
 "dname='" + dname + '\'' +
 '}';
 }
 }
 
 | 
创建Emp员工类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | public class Emp {private Dept dept;
 
 public Dept getDept() {
 return dept;
 }
 
 public void setDept(Dept dept) {
 this.dept = dept;
 }
 
 public void test(){
 System.out.println(dept);
 }
 
 @Override
 public String toString() {
 return "Emp{" +
 "dept=" + dept +
 '}';
 }
 }
 
 | 
配置xml文件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 
 
 
 
 
 
 <bean id="emp" class="com.along.autowire.Emp" autowire="byType">
 
 </bean>
 <bean id="dept" class="com.along.autowire.Dept"/>
 
 | 
创建测试类
| 12
 3
 4
 5
 6
 
 | @Testpublic void testEmp() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-autowire.xml");
 Emp emp = applicationContext.getBean("emp", Emp.class);
 System.out.println(emp);
 }
 
 | 
结果

外部属性文件注入
本次拿数据库连接池Druid(德鲁伊)举例子
导入druid,c3p0,mysql驱动(这些配套资料中有)
直接注入
| 12
 3
 4
 5
 6
 
 | <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
 <property name="url" value="jdbc:mysql://localhost:3306/mybatis_plus"/>
 <property name="name" value="root" />
 <property name="password" value="123456" />
 </bean>
 
 | 
外部注入
创建 jdbc.properties 文件
| 12
 3
 4
 
 | jdbc.driverClassName=com.mysql.cj.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mybatis_plus
 jdbc.userName=root
 jdbc.password=123456
 
 | 
引入命名空间 context
| 12
 3
 4
 5
 6
 7
 8
 
 | <?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"
 >
 </beans>
 
 | 
引入外部文件
| 1
 | <context:property-placeholder location="jdbc.properties" />
 | 
配置连接池
使用 ${} 表达式取到 jdbc.properties中的 key
| 12
 3
 4
 5
 6
 
 | <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/>
 <property name="url" value="${jdbc.url}"/>
 <property name="name" value="${jdbc.userName}"/>
 <property name="password" value="${jdbc.password}"/>
 </bean>
 
 | 
IOC操作Bean管理(注解方式)
这里推荐创建一个新的项目来学习
什么是注解
- 注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
- 使用注解,注解作用在类上面,方法上面,属性上面
- 使用注解目的:简化 xml 配置
针对 Bean 管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Respository 一般用在持久层中
上面四个注解的功能是一样的,都可以创建bean实例
基于注解方式创建对象
1.引入 SpringAop 依赖 (这里就不演示了,配套资料都有)
2.开启组件扫描
首先添加命名空间 context (不演示了,上面有)
| 12
 3
 4
 5
 6
 
 | 
 
 
 
 <context:component-scan base-package="com.along"></context:component-scan>
 
 | 
创建类,在类上方添加创建对象注解
注解中的value属性可以不写
默认值是类名称,首字母小写
UserService ==> userService
ProductDao ==> productDao
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Component(value = "userService")
 
 
 public class UserService {
 public void add(){
 System.out.println("service add ...");
 }
 }
 
 | 
测试代码
结果:
com.along.service.UserService@6293abcc
service add …
| 12
 3
 4
 5
 6
 7
 
 | @Testpublic void testService() {
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
 UserService userService = applicationContext.getBean("userService", UserService.class);
 System.out.println(userService);
 userService.add();
 }
 
 | 
组件扫描细节配置
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 
 
 
 
 <context:component-scan base-package="com.along" use-default-filters="false">
 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 </context:component-scan>
 
 
 
 
 
 
 
 <context:component-scan base-package="com.along" use-default-filters="false">
 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 </context:component-scan>
 
 | 
注解方式实现属性注入(稍微抽象)
- @Autowired:根据属性类型进行自动装配 - 
- 把service和dao对象创建,在service和dao类添加创建对象注解
- 在service注入dao对象,在 service 类添加dao类型属性,在属性上面使用注解
 
- @Qualifier:根据属性名称进行注入 - 
- @Qualifier 注解的使用,和上面@Autowired 一起使用 
- // 不用添加set方法
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
| 12
 3
 4
 5
 6
 7
 8
 
 | ```
 3. @Resource:可根据类型注入,可根据名称注入
 
 - ```java
 //@Resource //根据类型进行注入
 @Resource(name = "userDaoImpl1") //根据名称进行注入
 private UserDao userDao;
 
 |  
 
 
 
| 12
 3
 4
 5
 6
 
 | 4. @Value:注入普通类型属性
 
 - ```java
 @Value(value = "abc")
 private String name;
 
 | 
完全注解开发
创建配置类
| 12
 3
 4
 
 | @Configuration @ComponentScan(basePackages = {"com.along"})
 public class SpringConfig {
 }
 
 | 
编写测试类
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Testpublic void testService2() {
 
 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
 UserService userService = context.getBean("userService",UserService.class);
 System.out.println(userService);
 userService.add();
 }
 
 
 | 
Spring AOP
这里往后有些抽象
AOP概述
- 面向切面编程(AOP)通过提供另一种考虑程序结构的方法对面向对象编程(OOP)进行了补充。
- OOP中模块化的关键单元是类,而AOP中模块化的关键单元是aspect(切面)。
- Spring的关键组件之一是AOP框架。 虽然Spring IoC容器不依赖于AOP(这意味着如果您不想使用AOP就不需要),但AOP对Spring IoC进行了补充,提供了一个非常强大的企业级解决方案。
这里有几个名词需要了解一下:
- aop alliance:是AOP联盟,该组织定义了很多针对面向切面的接口api,通常Spring等其它具备动态织入功能的框架依赖此包。
- AspectJ:AOP虽然是方法论,但就好像OOP中的Java一样,一些先行者也开发了一套语言来支持AOP。目前用得比较火的就是AspectJ语言了,它是一种几乎和Java完全一样的语言,而且完全兼容Java。当然spring也有独立的AOP的实现。
AOP概念和术语
- Aspect(切面):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。
- Pointcut(切入点 ):匹配连接点(Joinpoint)的断言。通知和一个【切入点表】达式关联,并在满足这个切入点的连接点上运行。 【切入点表达式如何和连接点匹配】是AOP的核心:Spring缺省使用AspectJ切入点语法。
- Introduction(引入): Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。
- Target object(目标对象):被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。
- AOP代理 AOP proxy: 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- Weaving(织入):把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象,这个过程叫织入。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。
Spring AOP包括以下类型的通知:
- Before advice :在连接点之前运行的通知,但不能阻止执行流继续执行到连接点(除非它抛出异常)。
- After returning advice :在连接点正常完成后运行的通知(例如,如果方法返回而不引发异常)。
- After throwing advice:在方法通过抛出异常退出时运行的通知。
- After (finally) advice:不管连接点以何种方式退出(正常或异常返回),都要运行的通知。
- Around advice:围绕连接点(如方法调用)的通知。 这是最有力的建议。 Around通知可以在方法调用前后执行自定义行为。 它还负责选择是继续到连接点,还是通过返回自己的返回值或抛出异常来简化被通知的方法执行。
Spring AOP能力和目标
- Spring AOP是用纯Java实现的。 不需要特殊的编译过程。
- Spring AOP目前只支持【方法执行连接点】(在Spring bean上的方法上执行通知)。 如果需要通知字段访问和更新连接点,可以考虑使用AspectJ之类的语言
- Spring AOP的AOP方法不同于大多数其他AOP框架。 目的不是提供最完整的AOP实现(尽管Spring AOP很有能力)。 相反,其目的是提供AOP实现和Spring IOC之间的紧密集成,以帮助解决企业应用程序中的常见问题。
Spring和AspectJ
Spring框架的AOP功能通常与Spring IoC容器一起使用。 切面是通过使用普通beanDifination语法配置的。 使用Spring AOP不能轻松或有效地完成一些事情,比如通知非常细粒度的对象(通常是域对象)。 AspectJ是这种情况下的最佳选择。 然而,我们的经验是,Spring AOP为企业Java应用程序中的大多数问题提供了一个很好的解决方案。
Spring AOP从不与AspectJ竞争,以提供全面的AOP解决方案。 我们相信基于代理的框架(如Spring AOP)和成熟的框架(如AspectJ)都是有价值的,它们是互补的,而不是相互竞争的。Spring无缝地将Spring AOP和IoC与AspectJ集成在一起,以支持在一致的基于Spring的应用程序体系结构中使用AOP。 这种集成不会影响Spring AOP API或AOP Alliance API, Spring AOP保持向后兼容。
AOP代理
Spring AOP默认为AOP代理使用标准的JDK动态代理, 这允许代理任何接口(或接口集)。
Spring AOP也可以使用CGLIB代理。 缺省情况下,如果业务对象没有实现接口,则使用CGLIB。 由于编写接口是很好的实践,因此业务类通常实现一个或多个业务接口是可能的。
代码演示AOP代理:
这里最好懂得Java的反射机制,否则可能有点不好理解
引入依赖包
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 
 |       <dependency>
 <groupId>junit</groupId>
 <artifactId>junit</artifactId>
 <version>4.13.2</version>
 <scope>test</scope>
 </dependency>
 
 <dependency>
 <groupId>org.hamcrest</groupId>
 <artifactId>hamcrest</artifactId>
 <version>2.2</version>
 <scope>test</scope>
 </dependency>
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>5.2.18.RELEASE</version>
 </dependency>
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-beans</artifactId>
 <version>5.2.18.RELEASE</version>
 </dependency>
 
 <dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-context</artifactId>
 <version>5.2.18.RELEASE</version>
 </dependency>
 
 
 
 <dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjweaver</artifactId>
 <version>1.9.6</version>
 
 </dependency>
 <dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.2</version>
 </dependency>
 <dependency>
 <groupId>log4j</groupId>
 <artifactId>log4j</artifactId>
 <version>1.2.12</version>
 </dependency>
 
 | 
编写Service层代码
| 12
 3
 
 | public interface IUserService {void save();
 }
 
 | 
| 12
 3
 4
 5
 6
 
 | public class UserService implements IUserService {@Override
 public void save() {
 System.out.println("保存成功....");
 }
 }
 
 | 
编写Config类
AppConfig.java
| 12
 3
 4
 
 | @Configuration@ComponentScan("com.along")
 public class AppConfig {
 }
 
 | 
编写Bean的后置处理器
ProxyBeanPostProcessor
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | @Componentpublic class ProxyBeanPostProcessor implements BeanPostProcessor {
 
 
 
 
 @Override
 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 Object proxyBean = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 System.out.println("开启事务");
 try {
 Object invoke = method.invoke(bean, args);
 System.out.println("提交事务");
 return invoke;
 } catch (RuntimeException ex) {
 System.out.println("回滚");
 throw new RuntimeException("出异常了");
 }
 }
 });
 return proxyBean;
 }
 
 | 
添加主方法
App.java
| 12
 3
 4
 5
 6
 7
 
 | public class App {public static void main(String[] args) {
 ApplicationContext app = new AnnotationConfigApplicationContext(AppConfig.class);
 IUserService bean = app.getBean(IUserService.class);
 bean.save();
 }
 }
 
 | 
结果:
开启事务
保存成功….
提交事务
@AspectJ风格的支持
@AspectJ是将【切面】声明为带有注解的常规Java类的一种风格。 @AspectJ风格是由AspectJ项目open innew window作为AspectJ 5发行版的一部分引入的。 Spring与AspectJ5有相同的注解, 但是,AOP运行时仍然是纯Spring AOP,并且不依赖于AspectJ编译器或编织器。
要在Spring配置中使用@AspectJ注解,您需要启用Spring支持
开启AspectJ支持
注解方式开启
| 12
 3
 4
 5
 
 | @Configuration@ComponentScan("com.along")
 @EnableAspectJAutoProxy
 public class AppConfig {
 }
 
 | 
XML方式开启(记得打开apo命名空间)
声明一个切面
| 12
 3
 4
 5
 
 | @Aspect
 @Component
 public class MyAspect {
 }
 
 | 
通过组件扫描自动检测切面你可以在Spring XML配置中通过“@Configuration”类中的“@Bean”方法将切面类注册为常规bean,或者让Spring通过类路径扫描自动检测它——就像任何其他Spring管理的bean一样。 但是,请注意,“@Aspect”注解不足以实现类路中的自动检测。 为了达到这个目的,您需要添加一个单独的【@Component】注解。
声明一个切入点
怎么确定一个方法:public void com.ydlclass.service.impl.*(..)
支持切入点指示器
Spring AOP支持以下在切入点表达式中使用的AspectJ切入点指示器(PCD):



切入点表达式运算
可以使用’ &&’ || ‘和’ ! ‘组合切入点表达式。 您还可以通过名称引用切入点表达式。 下面的例子展示了三个切入点表达式:
| 12
 3
 4
 5
 6
 7
 8
 
 | @Pointcut("execution(public * *(..))")private void anyPublicOperation() {}
 
 @Pointcut("within(com.xyz.myapp.trading..*)")
 private void inTrading() {}
 
 @Pointcut("anyPublicOperation() && inTrading()")
 private void tradingOperation() {}
 
 | 
共享公共切入点定义
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | @Aspectpublic class CommonPointcuts {
 @Pointcut("within(com.xyz.myapp.web..*)")
 public void inWebLayer() {}
 
 @Pointcut("within(com.xyz.myapp.service..*)")
 public void inServiceLayer() {}
 
 @Pointcut("within(com.xyz.myapp.dao..*)")
 public void inDataAccessLayer() {}
 
 @Pointcut("execution(* com.xyz.myapp..service.*.*(..))")
 public void businessService() {}
 
 @Pointcut("execution(* com.xyz.myapp.dao.*.*(..))")
 public void dataAccessOperation() {}
 }
 
 | 
准备Service
UserService
| 12
 3
 4
 5
 6
 7
 
 | @Servicepublic class UserService implements IUserService {
 @Override
 public void register() {
 System.out.println("这是注册的方法");
 }
 }
 
 | 
OrderService
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | @Servicepublic class OrderService implements IOrderService {
 
 @Override
 public void order(Integer money) {
 
 System.out.println("这是order的方法");
 }
 }
 
 | 
ActivityService
| 12
 3
 4
 5
 6
 
 | public class ActivityService implements IActivityService {@Override
 public void sendGift() {
 System.out.println("送了礼物");
 }
 }
 
 | 
声明通知
Before advice)前置通知
@Before
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 
 
 @Before("beforePointcut()")
 private void beforeAdvice(JoinPoint jp) throws InvocationTargetException,
 
 IllegalAccessException {
 MethodSignature signature = (MethodSignature) jp.getSignature();
 
 Method method = signature.getMethod();
 
 method.invoke(jp.getTarget(), jp.getArgs());
 System.out.println("this is before advice");
 }
 
 | 
(After returning advice)返回通知
| 12
 3
 4
 5
 6
 7
 
 | 
 
 @AfterReturning("execution(public * com.along..order(..))")
 private void afterReturningAdvice() {
 System.out.println("This is afterReturningAdvice");
 }
 
 | 
(After throwing advice)抛出异常后通知
| 12
 3
 4
 5
 6
 7
 8
 
 | 
 
 @AfterThrowing(value = "execution(public * com.along..order(..))", throwing = "ex")
 private void afterThrowAdvice(ArithmeticException ex) {
 System.out.println("This is afterThrowAdvice");
 System.out.println("----------" + ex);
 }
 
 | 
After (Finally) 最终通知
| 12
 3
 4
 5
 6
 7
 
 | 
 
 @After("execution(public * com.along..order(..))")
 private void afterAdvice() {
 System.out.println("This is afterAdvice");
 }
 
 | 
Around通知
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | 
 
 
 
 
 
 @Around("execution(public * com.along..order(..))")
 private Object AroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
 System.out.println("This is AroundAdvice1");
 
 Object proceed = pjp.proceed();
 
 System.out.println("This is AroundAdvice2");
 return proceed;
 }
 
 | 
MyAspect.java 全部代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 
 | package com.along.aspectj;
 import com.along.service.IActivityService;
 import com.along.service.impl.ActivityService;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.Signature;
 import org.aspectj.lang.annotation.*;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.springframework.stereotype.Component;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 
 @Aspect
 @Component
 public class MyAspect {
 
 
 
 @DeclareParents(value = "com.along.service.impl.OrderService", defaultImpl = ActivityService.class)
 public static IActivityService activityService;
 
 
 @Pointcut("execution(public * com.along ..*(..))")
 private void beforePointcut() {
 }
 
 
 
 
 @Before("beforePointcut()")
 private void beforeAdvice(JoinPoint jp) throws InvocationTargetException,
 
 IllegalAccessException {
 MethodSignature signature = (MethodSignature) jp.getSignature();
 
 Method method = signature.getMethod();
 
 method.invoke(jp.getTarget(), jp.getArgs());
 System.out.println("this is before advice");
 }
 
 
 
 
 @AfterReturning("execution(public * com.along..order(..))")
 private void afterReturningAdvice() {
 System.out.println("This is afterReturningAdvice");
 }
 
 
 
 
 @After("execution(public * com.along..order(..))")
 private void afterAdvice() {
 System.out.println("This is afterAdvice");
 }
 
 
 
 
 @AfterThrowing(value = "execution(public * com.along..order(..))", throwing = "ex")
 private void afterThrowAdvice(ArithmeticException ex) {
 System.out.println("This is afterThrowAdvice");
 System.out.println("----------" + ex);
 }
 
 
 
 
 
 
 
 
 @Around("execution(public * com.along..order(..))")
 private Object AroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
 System.out.println("This is AroundAdvice1");
 
 Object proceed = pjp.proceed();
 System.out.println("This is AroundAdvice2");
 return proceed;
 }
 
 @Before("execution(* com.along.service.impl.OrderService.*(..)) && args(money,..)")
 public void validateAccount(Integer money) {
 System.out.println("before-----" + money);
 }
 
 
 }
 
 
 | 
通知的参数(XML演示)
Spring提供了完整类型的通知,这意味着您可以在【通知签名】中声明【所需的参数】(就像我们前面在返回和抛出示例中看到的那样)。
访问当前 JoinPoint
- getArgs(): 返回方法参数。
- getThis(): 返回代理对象。
- getTarget(): 返回目标对象。
- getSignature(): 返回被通知的方法的签名。
- toString(): 打印被建议的方法的有用描述。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | <bean id="myAop" class="com.along.aspectj.MyAop"/><bean id="orderService" class="com.along.service.impl.OrderService"/>
 <bean id="userService" class="com.along.service.impl.UserService"/>
 <aop:config>
 <aop:aspect id="myaspect" ref="myAop">
 <aop:pointcut id="pointcut" expression="execution(* com.along..*(..))"/>
 <aop:before method="beforeAdvice" pointcut="execution(* com.along..*(..))"/>
 <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointcut"/>
 <aop:after-throwing method="afterThrowAdvice" throwing="ex" pointcut-ref="pointcut"/>
 <aop:after method="afterAdvice" pointcut-ref="pointcut"/>
 <aop:around method="AroundAdvice" pointcut="execution(* com.along..*(..)) and args(money,..)"/>
 </aop:aspect>
 </aop:config>
 
 | 
切入点表达式的’ args(money,..) ‘部分有两个目的
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | public class MyAop {private void beforeAdvice(JoinPoint jp) throws InvocationTargetException,
 
 IllegalAccessException {
 MethodSignature signature = (MethodSignature) jp.getSignature();
 
 Method method = signature.getMethod();
 
 method.invoke(jp.getTarget(), jp.getArgs());
 System.out.println("this is before advice");
 }
 
 private void afterReturningAdvice() {
 System.out.println("This is afterReturningAdvice");
 }
 
 private void afterAdvice() {
 System.out.println("This is afterAdvice");
 }
 
 private void afterThrowAdvice(ArithmeticException ex) {
 System.out.println("This is afterThrowAdvice");
 System.out.println("----------" + ex);
 }
 
 private Object AroundAdvice(ProceedingJoinPoint pjp, Integer money) throws Throwable {
 System.out.println("This is AroundAdvice1");
 System.out.println("-----------" + money);
 
 Object proceed = pjp.proceed();
 System.out.println("This is AroundAdvice2");
 return proceed;
 }
 }
 
 | 
Main方法
| 12
 3
 4
 5
 6
 7
 
 | public class AppByXml {public static void main(String[] args) {
 ApplicationContext app = new ClassPathXmlApplicationContext("aop.xml");
 IOrderService bean = app.getBean(IOrderService.class);
 bean.order(100);
 }
 }
 
 | 
将参数传递给Advice
- 首先,它限制只匹配哪些方法执行,其中方法接受至少一个参数,并且传递给该参数的参数是’ Account ‘的一个实例。
- 其次,它通过’ Account ‘参数使通知可以使用实际的’ Account ‘对象。
引入Introduction
引入使切面能够声明被通知的对象【实现给定的接口】,也就是让代理对象实现新的接口。
| 12
 3
 4
 5
 6
 
 | 
 
 
 @DeclareParents(value = "com.along.service.impl.OrderService", defaultImpl = ActivityService.class)
 public static IActivityService activityService;
 
 | 
运行
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | public class App {public static void main(String[] args) {
 ApplicationContext app = new AnnotationConfigApplicationContext(AppConfig.class);
 IOrderService bean = app.getBean(IOrderService.class);
 bean.order(10000);
 
 IActivityService bean1 = app.getBean(IActivityService.class);
 bean1.sendGift();
 }
 }
 
 | 
基于schema的AOP支持(XML)
配置切面,切点表达式,通知
配置命名空间
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | <?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 https://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
 
 </beans>
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | <?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 https://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
 
 
 
 <aop:config>
 <aop:aspect ref="aop">
 <aop:pointcut id="pointcut" expression="execution(* com.along..*(..))"/>
 <aop:before method="beforeAdvice" pointcut="execution(* com.along..*(..))"/>
 <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointcut"/>
 <aop:after-throwing method="afterThrowAdvice" throwing="ex" pointcut-ref="pointcut"/>
 <aop:after method="afterAdvice" pointcut-ref="pointcut"/>
 <aop:around method="AroundAdvice" pointcut="execution(* com.along..*(..)) and args(money,..)"/>
 </aop:aspect>
 </aop:config>
 
 <bean id="aop" class="com.along.aspecj.MyAop"/>
 <bean id="orderService" class="com.ydlclass.service.impl.OrderService"/>
 <bean id="userService" class="com.ydlclass.service.impl.UserService"/>
 </beans>
 
 | 
Introduction
| 12
 3
 4
 5
 6
 7
 8
 
 | <aop:aspect id="usageTrackerAspect" ref="usageTracking">
 <aop:declare-parents
 types-matching="com.xzy.myapp.service.*+"
 implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
 default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
 
 </aop:aspect>
 
 | 
MyAop
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | public class MyAop {private void beforeAdvice(JoinPoint jp) throws InvocationTargetException,
 
 IllegalAccessException {
 MethodSignature signature = (MethodSignature) jp.getSignature();
 
 Method method = signature.getMethod();
 
 method.invoke(jp.getTarget(), jp.getArgs());
 System.out.println("this is before advice");
 }
 
 private void afterReturningAdvice() {
 System.out.println("This is afterReturningAdvice");
 }
 
 private void afterAdvice() {
 System.out.println("This is afterAdvice");
 }
 
 private void afterThrowAdvice(ArithmeticException ex) {
 System.out.println("This is afterThrowAdvice");
 System.out.println("----------" + ex);
 }
 
 private Object AroundAdvice(ProceedingJoinPoint pjp, Integer money) throws Throwable {
 System.out.println("This is AroundAdvice1");
 System.out.println("-----------" + money);
 
 Object proceed = pjp.proceed();
 System.out.println("This is AroundAdvice2");
 return proceed;
 }
 }
 
 | 
选择使用哪种AOP声明风格
一旦您确定使用aop是实现给定需求的最佳方法,您如何决定是使用Spring AOP还是Aspect?是使用@AspectJ注解风格还是Spring XML风格?
 如果您选择使用Spring AOP,那么您可以选择【@AspectJ或XML】样式。
 XML样式可能是现有Spring用户最熟悉的,并且它是由真正的【pojo支持】(侵入性很低)的。 当使用AOP作为配置企业服务的工具时,XML可能是一个很好的选择(一个很好的理由是您【是否认为切入点表达式】 是需要【独立更改】的一部分配置)。使用XML样式,可以从配置中更清楚地看出系统中存在哪些切面。
 XML样式有两个缺点。 首先,它没有将它所处理的需求的实现完全封装在一个地方。 其次,与@AspectJ风格相比,XML风格在它能表达的内容上稍微受到一些限制,不可能在XML中声明的命名切入点进行组合。 例如,在@AspectJ风格中,你可以写如下内容:
| 12
 3
 4
 5
 6
 7
 8
 
 | @Pointcut("execution(* get*())")public void propertyAccess() {}
 
 @Pointcut("execution(org.xyz.Account+ *(..))")
 public void operationReturningAnAccount() {}
 
 @Pointcut("propertyAccess() && operationReturningAnAccount()")
 public void accountPropertyAccess() {}
 
 | 
在XML样式中,可以声明前两个切入点:
| 12
 3
 4
 5
 
 | <aop:pointcut id="propertyAccess"expression="execution(* get*())"/>
 
 <aop:pointcut id="operationReturningAnAccount"
 expression="execution(org.xyz.Account+ *(..))"/>
 
 | 
XML方法的缺点是不能通过组合这些定义来定义“accountPropertyAccess”切入点。
@AspectJ还有一个优点,即@AspectJ切面可以被Spring AOP和AspectJ理解(从而被使用)。 因此,如果您以后决定需要AspectJ的功能来实现额外的需求,您可以轻松地迁移到经典的AspectJ当中。
总的来说,Spring团队更喜欢自定义切面的@AspectJ风格,而不是简单的企业服务配置。
以编程方式创建@AspectJ代理
除了通过使用<aop:config> 或<aop:aspectj-autoproxy>在配置中声明方面之外,还可以通过编程方式创建通知目标对象的代理。
代码如下,这只是一个小例子,用来看一下spring是怎么封装代理的:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | public class MyTest {public static void main(String[] args) {
 AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(new OrderService());
 aspectJProxyFactory.addAspect(MyAspect.class);
 IOrderService proxy =
 (IOrderService) aspectJProxyFactory.getProxy();
 proxy.order(111);
 }
 }
 
 | 
Spring事务(编写中)