spring是什么?
简介:
- Spring:春天------->给软件行业带来了春天
- 2002年首次推出了Spring框架的雏形:interface21框架!
- spring于2003年兴起的一个轻量级的IOC和AOP的java开发框架,为了简化企业级开发而生的
特点 - 轻量级:jar包小,运行消耗内存资源小,核心包小
- 开源的免费框架
理念 - 使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
非侵入式 - spring框架代码不会侵入到我们的业务代码(用户管理 servlet service dao)
UserSelevt extends HttpServlet(侵入式)
IOC - 即Inversion of Control 缩写IOC 控制反转(把什么控制权反转给谁 以前写的代码,哪里需要对象就在哪里new一个对象)
AOP - 面向切面 为Aspect(切面) Oriented Programming
开发出了第一版程序 saveStudent(){ }该原来的代码
绑定(配置)
saveLog(){}
后来要在第一版的基础上添加功能(保存日志,管理事务 sqlseesion.commit())
AOP的思想是 可以帮我们动态代理的调用,而不需要修改代码
一站式
它是一个后端管理框架,集基础容器,数据访问(jdbc,事务管理),web(Servlet),Aop为一身的一站式框架
Spring搭建
第一步:导入jar包
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
第二步:创建类
第三步:创建spring配置文件
第四步:测试spring
创建new ClassPathXmlApplicationContext(“spring,xml”);spring容器
获取spring创建的bean对象
注解:
创建对象:
@Component
@Scope
@Repository
@Service
@Controller
注入对象:
@Autowired(required=true)添加在属性,set方法 ,构造方法 是spring提供的注解标签 支持byName byType
@autowired(required=true)默认 注入值不能为空 是根据属性的类型自动注入(根据属性的类型在spring容器中查找) byType
也可以通过对象名查找注入,需要结合@Qualifier(value=" ")
JDK中的注入:
@Resource(name=“对象名”)是JDK自身提供的注解表奇案,也有byName和byType两种注入方式
IOC:spring创建对象
DI:Dependency Injection依赖注入 为创建好的对象属性注入值
构造方法注入
属性set方法注入
注解与xml的对比
注解的优点:方便直观高效(代码量少,没有配置文件那么复杂)
注解的缺点:以硬编码的方式写入java代码中,修改需要重新编译代码
xml的优点:配置和代码是分离的,修改xml代码无需重新编译,直接修改,修改完成之后,
只需要重启服务器即可将新的配置加载
xml的缺点:编写过于麻烦,效率低,大型项目应用过于复杂
Spring JDBC模块
spring是一个一站式框架,提供了对JDBC的管理封装
封装一个JdbcTempate模板类,提供用于执行sql的方法
JDBC模块对数据库事务进行管理
spring数据链接不直接参与和数据库的连接
可以使用一些第三方的组件连接数据库
DECP c3p0 阿里druid(德鲁伊)数据库连接组件 自身还提供了数据库连接池技术 sql监控
三大功能:
1.数据库连接,封装了jdbc
2.数据库连接池 频繁的连接数据库
创建销毁连接对象 Connection SqlSession 开销大
创建一个连接对象的池子 与数据库交互时,
可以先从连接池中获取连接
用完后不进行销毁,只是还回到连接池中 减少创建销毁的开销
让spring来管理创建Druid数据库连接对象
jdbcTemplate中常用的方法
execute:无返回值,可执行ddl,增删改语句
updata:执行新增、修改 删除语句
queryFor...:执行查询相关语句
不适用AOP的开发方式
先定义好接口与一个实现类,该实现类中除了要实现接口中的方法外,还要再写两个非业务方法,非业务方法也称为交叉业务逻辑;
doTransaction():用于事务处理
doLog():用于日志处理
然后,在使用接口口调用它们,接口的方法也称为主业务逻辑
AOP概述
AOP为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
AOP是OOP的延续,是软件开发中的一个热点也是Spring框架中的一个重要的内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
AOP OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想,OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果,这两种设计思想在目标上有着本质的差异
面向切面编程的好处就是:减少重复,专注业务
注意 :面向切面编程知识面向对象编程的一种补充
核心原理
使用动态代理的方式在执行方法前后或者出现异常的时候做加入相关的逻辑
使用案例
事务处理:开启事务,关闭事务 出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理
AOP的基本概念
连接点:类中可以被增强的方法,这个方法就叫连接点
切入点:类中有很多方法可以被增强,但实际只有add和update被增加了,那么add和update方法就被称为是切入点
通知:在连接点上要做的事情(分为:前置通知 后置通知 异常通知 环绕通知 最终通知)
切面:把通知添加到连接点的过程
目标:要增强的类
代理:向目标对象应用通知之后创建的代理对象
springAOP实现
对于AOP这种编程思想,很多框架都进行了实现,spring就是其中之一,可以完成面向切面编程
然而,AspectJ也实现了AOP的功能,AepectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发,所以Spring又将AspectJ的对于AOP的实现方式也引入到了自己的框架中
在Spring中使用AOP开发时,一般使用AspectJ的实现方式
AspectJ是一个优秀面向切面的框架,它扩展了java语言,提供了强大的切面实现
spring事务管理
事务可以看做是由对数据库若干操作组成的一个单元
我们在开发企业应用时,对于业务人员的一个操作实际是对数据读写的多部操作的结合,由于数据操作在顺序执行的过程,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻辑并未正确的完成,要么都取消,从而保证数据满足一致性的要求
Spring中的事务管理分为两种,一种是编程式事务,一种是声明式事务
编程式事务在项目中很少使用,这种方式需要注入一个事务管理对象TransactionTemplate,然后在我们代码中需要提交事务或回滚事务时自己写入代码实现
声明式事务管理建立在 AOP 基础上,本质是对方法前后进行拦截,所以声明式
事务是方法级别的。
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!-- commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
<!-- 阿里数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--spring-mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
依赖注入
public class Student{
private String name;
private String address;
private String[] books ;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> game;
private String wife;
private Properties info;
}
第一种,普通的注入
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="name" value="张三">
</bean>
第二种,Bean注入,ref
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="address" ref="address">
<property name="address" value="陕西西安">
</bean>
数组
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
<value>三国演义</value>
</array>
</property>
</bean>
List
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="hobbys">
<list>
<value>学习</value>
<value>听歌</value>
<value>敲代码</value>
<value>看电影</value>
</list>
</property>
</bean>
Map
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="card">
<map>
<entry key="身份证" value="610000000000000000"/>
<entry key="银行卡" value="231561213560000000000000000000000000"/>
<entry key="学生卡" value="222123232523262363"/>
</map>
</property>
</bean>
Set
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="games">
<set>
<value>LOL</value>
<value>穿越火线</value>
<value>地下城</value>
<value>王者荣耀</value>
</set>
</property>
</bean>
null
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="wife">
<null/>
</property>
</bean>
Properties
<bean id="student" class="com.ffyc.spring.pojo.Student">
<property name="info">
<props>
<prop key="学号">20210101</prop>
<prop key="姓名">张三</prop>
<prop key="性别">男</prop>
<prop key="专业">计算机</prop>
</props>
</property>
</bean>
扩展方式注入
c命名与p命名空间注入
p命名空间注入
1.导入配置文件
c命名与p命名空间注入配置:
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--配置我们项目中的类,配置进来后spring就对其管理(sheng)-->
<!--id:生成对象的标识
class:类的地址
name:对象的别名,可以为多个
scope:
singleton:单例的,整个应用程序中只创建一次多次获取是同一个,再spring容器启动时就创建
prototype:原型的(多例的),每次获取时会创建一个新对象
c命名与p命名空间注入配置:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
-->
<!--p命名空间注入,可以直接注入属性的值:peroperty-->
<bean id="userp" class="com.ffyc.spring.model.User" p:name="钱三强" p:age="27"></bean>
<!--c命名空间注入,可以通过构造器注入:constructs-->
<bean id="userc" class="com.ffyc.spring.model.User" c:name="小李飞刀" c:age="22"></bean>
测试
package com.ffyc.spring.test;
import com.ffyc.spring.model.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test3 {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("spring.xml");
//对p命名空间注入测试
User userp = app.getBean("userp", User.class);
//对c命名空间注入测试
User userc = app.getBean("userc", User.class);
System.out.println(userp);
System.out.println(userc);
}
}
输出
注意:p命名和c命名空间不能直接使用,需要导入xml约束!
c命名与p命名空间注入配置:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
bean作用域
1.代理模式(Spring默认机制)
- singleton:单例的,整个应用程序中只创建一次多次获取是同一个,再spring容器启动时就创建
<bean id="user3" calss="com.ffyc.model.User" scope="singleton"/>
2.原型模式
- prototype:原型的(多例的),每次获取时会创建一个新对象
<bean id="user3" calss="com.ffyc.model.User" scope="prototype"/>
3.其余的 request,session application,这些只能在web开发中使用到!
Baen的自动装配
- 自动装配是Spring满足bean依赖一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性
在Spring中有三种装配的方式
1.在xml中显示的配置
2.在java中显示配置
3.隐式的自动装配bean [重要]
测试
1.环境搭建
一个人有两个宠物
package com.ffy.spring.model;
public class Cat {
public void shout(){
System.out.println("miao~");
}
}
package com.ffy.spring.model;
public class Dog {
public void shout(){
System.out.println("wang~");
}
}
package com.ffy.spring.model;
public class People {
private Cat cat;
private Dog dog;
private String name;
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<?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">
<!--导入三个莫model-->
<bean id="cat" class="com.ffy.spring.model.Cat"></bean>
<bean id="dog" class="com.ffy.spring.model.Dog"></bean>
<bean id="people" class="com.ffy.spring.model.People">
<property name="name" value="西门吹雪"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
</beans>
测试
import com.ffy.spring.model.People;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
People people =app.getBean("people", People.class);
people.getDog().shout();
people.getCat().shout();
System.out.println(people.getName());
}
}
ByName自动装配
<bean id="cat" class="com.ffy.spring.model.Cat"></bean>
<bean id="dog" class="com.ffy.spring.model.Dog"></bean>
<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.ffy.spring.model.People" autowire="byName">
<property name="name" value="西门吹雪"></property>
</bean>
ByType自动装配
<bean class="com.ffy.spring.model.Cat"></bean>
<bean id="dog" class="com.ffy.spring.model.Dog"></bean>
<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的beanid-->
<bean id="people" class="com.ffy.spring.model.People" autowire="byType">
<property name="name" value="西门吹雪"></property>
</bean>
小结:
- byName的时候,需要保证所有bean的id名唯一,并且这个bean需要和自动注入属性的set方法的值一致!
- byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入属性的类型一致![byType的时候可以不给beanid]
使用注解实现自动装配
jdk1.5支持的注解,spring2.5支持的注解
要使用注解须知:
1.导入约束:context约束
2.配置注解的支持 :context:annotation-config/
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
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/>
</beans>
>
autowird
- 直接在属性上使用即可!也可以在set方式上使用
- 使用Autowired我么可以不用编写Set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中,存在且符合名字(byName)
科普
@Nullable 字段标记了这个注解,说明这个字段可以为null;
public @interface Autowired {
boolean required() default true;
}
public class People {
//如果显示定义了Autowired的required = false说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
private String name;
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解[@Autowired]完成的时候,我们使用 @Qualifier(value = “xxxxx”)去配和@Autowired的使用,指定一个唯一的bean对象注入!
public class People {
//如果显示定义了Autowired的required = false说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
@resource(name="cat111");
private Cat cat;
@Autowired
private Dog dog;
private String name;
小结
@resource和@Autowired的区别
- 都是用来自动装配的都可以放在属性属性字段上
- @Autowired通过byTyoe的方式实现,而且必须要求这个对象存在![常用]
- @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下就会报错!
- 执行顺序不同
@Autowired通过byTyoe的方式实现;
@Resource默认通过byName的方式实现,
使用注解开发
在spring4之后,要使用注解开发,必须要保证aop的包导入了
使用注解需要导入context约束,增加注解支持!
1.bean
2.属性如何注入
package com.ffyc.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//等价于<bean id="user" class="com.ffyc.model.User"></bean>
//@Component组件
@Component
public class User {
@Value("木易")
//相当于 <property name="name" value="木易"></property>
public String name;
}
3.衍生的注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层构架分层!
- dao [@Repository]
- service [@Service]
- controller [Controller]
这四个注解的功能都是一样的,都是代表将某个类注册到Spring中,装配bean!
4.自动装配
5.作用域
6.小结
xml与注解
- xml更加万能,适用于任何场合,维护建档方便
- 注解不是自己的类使用不了,维护相对复杂
xml与注解的最佳实现 - xml 用来管理bean;
- 注解只负责完成属性的注入;
- 我们在使用的过程中只需要注意一个问题:必须让直接生效,就需要开启注解支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.ffyc"/>
<context:annotation-config/>
使用java的方式配置Spring
我们现在完全不使用Spring的xml配置了,全权交给java来做!
javaConfig是Spring的一个子项目,在Spring4之后,他成了一个核心功能!
实体类
package com.ffyc.model;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//这里这个注解的意思,就是说明这个类被spring接管了,注册到了容器中
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("木易")//属性注入值
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置类
package com.ffyc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.ffyc.model.User;
@Configuration//这个也会被spring容器托管,注册到容器中,因为它本来就是一个@Component
//@Configuration代表这是一个配置类,和之前的beans.xml一样
@ComponentScan("com.ffyc.model")
public class MyConfig {
//注册一个bean就相当与我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性,
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();//就是返回要注入到bean的对象
}
}
代理模式
为什么要学习代理模式?
因为这就是springAOP的底层![SpringAOP 和SpringMVC]
静态代理
角色分析:
- 抽象角色:一般会使用接口或者抽象类 来解决
- 真实角色:被代理的角色
- 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
- 客户:访问代理对象的人
//租房
public interface Rent{
public void rent();
}
public calss Host implements Rent{
public void rent(){
System.out.println(" 房东要出租房子");
}
}
public calss Client{
public static void main(String[ ] args ){
Host host =new Host();
host.rent();
}
}
public class Proxy implements Rent{
private Host host;
public Proxy(){
}
public Proxy(Host host){
this.host=host;
}
public void rent(){
host.rent();
}
//看房
public void seeHouse(){
System.out.print("中介带你看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
```java
public calss Client{
public static void main(String[ ] args ){
//Host host =new Host();
//host.rent();
//房东要出租房子
Host host =new Host();
//代理,中介帮房东出租房子,但是,代理角色一般会有一些附属操作
Proxy proxy =new proxy(host);
//你不用面对房东,直接找中介租房子即可!
proxy.rent():
}
}
代理模式的好处
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务。
- 公共业务也就交代给代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
缺点:
- 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低;
动态代理
-
动态代理和静态代理角色一样
-
动态代理的代理类时动态生成的,不是我们直接写好的!
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口—JDK动态代理
- 基于类:cglib
- java字节码实现:javasist
需要了解两个类:proxy:代理,invocationHandler:调用处理程序
动态代理的好处
- 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务。
- 公共业务也就交代给代理角色!实现了业务的分工!
- 公共业务发生扩展的时候,方便集中管理!
- 一个动态代理类代理的是一个接口,一般就是对应的一类业务!
AOP
什么是面想切面编程
- 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
使用Spring实现aop
要使用aop,需要导入一个依赖包
<!--https://mvnrepository.com/artifact/org.aspectj/aspectjweaver-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一:使用spring的API接口
public class Log implements MethodBeforeAdvice{
//method :要执行的目标对象的方法
//orgs :参数
//target: 目标对象
public void before(Method method,Object[] args,Object target) throws Throwable{
System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
面向切面编程的好处就是:减少晨读,专注业务
注意:面向切面编程只是面向对象编程的一种补充
核心原理:
使用动态代理的方式执行方法前后或者出现异常的时候加入相关的逻辑
使用案例
事务处理:开启事务,关闭事务,出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理
AOP的基本概念
连接点:
类中可以被增强的方法,这个方法就被称为连接点
切入点:
类中有很多方法可以被增强,但实际中只有add和update被增强了,那么add和update方法就被称为切入点(实际实现的连接点)
通知:
通知是指一个切面在特定的连接点要做的事情(增强的功能).通知分为方法执行前通知,方法执行后通知,环绕通知等等
切面:
把通知添加到切入点的过程叫切面
目标:
代理的目标对象(要增强的类)
代理:
向目标对象引用通知后,创建的代理对象
springAOP实现
对于aop这种编程的思想,很多框架都进行了实现,spring就是其中之一,可以完成面向切面编程
然而,AspectJ也实现了AOP的功能,AspectJ是一个居于Java语言的AOP框架,它提供了强大的AOP功能,且其实现方式更加简洁,使用更为方便,而且还支持注解式开发,所以,Spring又将AspectJ的对于AOP的实现也引入到了自己的框架中.
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。
AspectJ 是一个优秀面向切面的框架,它扩展了 Java 语言,提供了强大的切
面实现。
AspectJ 中常用的通知有五种类型:
前置通知,后置通知,环绕通知,异常通知,最终通知.
相关jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
基于 aspectj 的xml配置实现方式
<bean id="aopdemo" class="com.ff.spring.aop.AopDemo"></bean>
<aop:config>
<!-- 配置切入点 -->
<aop:pointcut expression="execution(*
com.ff.spring.service.UserService.adduser(..))" id="adduser"/>
<aop:pointcut expression="execution(*
com.ff.spring.service.UserService.*(..))" id="allmethod"/>
<!-- 配置通知和切入点 -->
<aop:aspect ref="aopdemo">
<aop:before method="savelog" pointcut-ref="adduser"/>
<aop:after method="savelog" pointcut-ref="adduser"/>
<aop:around method="aroundAdvice" pointcut-ref="adduser"/>
<aop:after-throwing method="exceptionAdvice" pointcut-ref="allmethod"
throwing="e" />
</aop:aspect>
</aop:config>
装有通知的类
基于注解方式的实现
启动AspectJ支持:aop:aspectJ-autoproxy/
@Component
@Aspect
public class AOPDemo {
@Before("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void before(){
System.out.println("before");
}
@After("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void after(){
System.out.println("after");
}
@Around("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("start");
point.proceed();
System.out.println("end");
}
@AfterThrowing(value = "execution(* com.ff.spring.demo1.dao.UserDao.*(..))",throwing = "e")
public void afterthrow(Throwable){
System.out.println("afterthrow");
}
@AfterReturning("execution(* com.ff.spring.demo1.dao.UserDao.*(..))")
public void afterreturn(){
System.out.println("afterreturn");
}
}
Sping集成Mybatis
Spring集成Mybatis其核心是将SqlSessionFactory 交由 Spring 管理,并由
Spring 管理对 dao 接口的代理实现。
导入mybatis jar包
Spring结合mybatis插件包
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
配置 sqlSessionFacto
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="mybatis-config.xml"></property>
<property name="mapperLocations" value="com/ff/*Mapper.xml">
</property>
</bean>
指定生成接口代理
<bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.ff.ssm.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
</property>
</bean>
在service中注入Dao代理接口,此接口有Spring代理实现
@AutoWired
DeptDao deptDao;