本文已参与「新人创作礼」活动,一起敞开创作之路。
前语
本博文专用于软件立异实验室 Spring
结构讲堂,由于讲堂时刻有限,选取了 Spring
结构中比较要点的几个来介绍。 Spring
结构的诞生是为了使开发愈加高效简洁,一起削减耦合程度,首要仍是思维上的一个改变,想要深入了解 Spring
结构的,能够查阅 Spring 官方文档,也推荐一下狂神老师的视频教育,值得一看。
初识Spring
简介
2002年,Rod Jahnson首次推出了 Spring
结构雏形 interface21
结构,
2004年3月24日,Spring
结构以 interface21
结构为根底,经过重新规划,发布了1.0正式版,
Spring理念 : 使现有技能愈加实用 , 自身便是一个大杂烩 , 整合现有的结构技能,
官网:spring.io/
官方下载地址:repo.spring.io/libs-releas…
GitHub:github.com/spring-proj…
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
组成
Spring
结构是一个分层架构,由 7 个界说杰出的模块组成。Spring
模块构建在中心容器之上,中心容器界说了创立、装备和办理 bean
的办法 。
组成 Spring
结构的每个模块(或组件)都能够单独存在,或许与其他一个或多个模块联合完结。每个模块的功用如下:
中心容器(Spring Core)
中心容器供给 Spring 结构的基本功用。Spring 以 bean 的办法安排和办理 Java 运用中的各个组件及其联系。Spring 运用 BeanFactory 来产生和办理 Bean,它是工厂办法的完结。BeanFactory 运用操控回转(IoC)办法将运用的装备和依靠性标准与实践的运用程序代码分隔。
运用上下文(Spring Context)
Spring 上下文是一个装备文件,向 Spring 结构供给上下文信息。Spring 上下文包含企业服务,如 JNDI、EJB、电子邮件、国际化、校验和调度功用。
Spring面向切面编程(Spring AOP)
经过装备办理特性,Spring AOP 模块直接将面向方面的编程功用集成到了 Spring 结构中。所以,能够很容易地使 Spring 结构办理的任何方针支撑 AOP。Spring AOP 模块为基于 Spring 的运用程序中的方针供给了事务办理服务。经过运用 Spring AOP,不必依靠 EJB 组件,就能够将声明性事务办理集成到运用程序中。
JDBC和DAO模块(Spring DAO)
JDBC、DAO 的笼统层供给了有意义的反常层次结构,可用该结构来办理反常处理,和不同数据库供货商所抛出的错误信息。反常层次结构简化了错误处理,并且极大的下降了需求编写的代码数量,比方翻开和关闭链接。
方针实体映射(Spring ORM)
Spring 结构刺进了若干个 ORM 结构,然后供给了 ORM 方针的联系工具,其间包含了 Hibernate、JDO 和 IBatis SQL Map 等,一切这些都遵从 Spring 的通用事物和 DAO 反常层次结构。
Web模块(Spring Web)
Web上下文模块建立在运用程序上下文模块之上,为基于web的运用程序供给了上下文。所以 Spring 结构支撑与 Struts 集成,web 模块还简化了处理多部分恳求以及将恳求参数绑定到域方针的工作。
MVC模块(Spring Web MVC)
MVC 结构是一个全功用的构建 Web 运用程序的 MVC 完结。经过策略接口,MVC 结构变成为高度可装备的。MVC 容纳了很多视图技能,其间包含 JSP、POI 等,模型来有 JavaBean 来构成,存放于 m 傍边,而视图是一个街口,负责完结模型,操控器表明逻辑代码,由 c 的事情。Spring 结构的功用能够用在任何 J2EE 服务器傍边,大多数功用也适用于不受办理的环境。Spring 的中心要点便是支撑不绑定到特定 J2EE 服务的可重用事务和数据的访问的方针,毫无疑问这样的方针能够在不同的 J2EE 环境,独立运用程序和测验环境之间重用。
创立
新建一个 Maven 项目,在 pom.xml
中进行装备,
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
目录
先编写一个 User
实体类,User.java
,
package com.idiot.pojo;
public class User{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Hello{" +
"name='" + name + '\'' +
'}';
}
}
再编写咱们的Spring
文件,这儿命名为beans.xml
,
装备文件可在官方文档中获取,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--运用Spring来创立方针,在Spring中这些都称为Bean-->
<!--bean便是java方针 , 由Spring创立和办理-->
<bean id="helloSpring" class="com.idiot.pojo.User">
<property name="name" value="Spring"/>
</bean>
</beans>
最终进行测验,MyTest.java
,
import com.idiot.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文方针
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//咱们的方针现在都在Spring中办理,咱们要运用的话,直接从里边取出来
User helloSpring = (User) context.getBean("helloSpring");
System.out.println(helloSpring.toString());
}
}
运转成果
装备阐明
别号
假如添加了别号,咱们也能够运用别号获取这个方针,原名也是能够运用的,在 beans.xml
中进行装备,
<alias name="helloSpring" alias="helloAlias"/>
<bean id="helloSpring" class="com.idiot.pojo.User">
<property name="name" value="Spring"/>
</bean>
Bean的装备
bean
便是 java
方针,由 Spring
创立和办理,
-
id
:bean
的仅有标识符,也就相当于方针名, -
class
:bean
方针所对应的全限定名:包名+类型, -
name
:也是别号,并且name
能够一起取多个别号,能够用逗号,分号,空格隔开,
假如没有装备 id
,name
便是默许标识符,
假如装备了 id
,又装备了 name
,那么 name
是别号,
假如不装备 id
和 name
,能够根据 applicationContext.getBean(.class)
获取方针,
import
import
一般用于团队开发运用,它能够将多个装备文件导入兼并成为一个,
假设现在项目中有多个人开发,其间三个人负责不同的类的开发,不同的类需求注册在不同的bean
装备文件中,咱们能够运用import
将一切人的beans.xml
兼并成一个总的,即applicationContext.xml
,
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
运用的时分直接运用总装备applicationContext.xml
即可。
思考
-
User
方针是谁创立的?-
User
方针是由Spring
创立的,<bean id="helloSpring" class="com.idiot.pojo.User"> <property name="name" value="Spring"/> </bean>
类型 变量名 = new 类型(); User user = new User(); id = 变量名 class = new的方针 property相当于给方针中的特点设值
-
-
User
方针的特点是怎样设置的?-
User
方针的特点是由Spring
容器设置的,
-
这个过程就叫操控回转:
- 操控:谁来操控方针的创立,传统运用程序的方针是由程序自身操控创立的,运用
Spring
后,方针是由Spring
来创立的, - 回转:程序自身不创立方针,而变成被迫的接收方针,
依靠注入:便是运用set
办法来进行注入的,
IOC
是一种编程思维,由主动的编程变成被迫的接收,能够经过newClassPathXmlApplicationContext
去阅读一下底层源码,
IOC
实质
操控回转IoC(Inversion of Control),是一种规划思维,是一种经过描绘(XML
或注解)并经过第三方去生产或获取特定方针的办法,在 Spring
中完结操控回转的是 IoC
容器,其完结办法是依靠注入(Dependency Injection,DI), 也有人认为 DI 仅仅 IoC 的另一种说法。没有 IoC 的程序中 , 咱们运用面向方针编程 , 方针的创立与方针间的依靠联系完全硬编码在程序中,方针的创立由程序自己操控,操控回转后将方针的创立转移给第三方,个人认为所谓操控回转便是:取得依靠方针的办法回转了。
IoC
是 Spring
结构的中心内容,运用多种办法完美的完结了 IoC
,能够运用 XML
装备,也能够运用注解,新版本的 Spring
也能够零装备完结 IoC
。
选用 XML
办法装备 Bean
的时分,Bean
的界说信息和完结是分离的,而选用注解的办法能够把两者合为一体,Bean
的界说信息直接以注解的办法界说在完结类中,然后达到了零装备的意图。
理论推导
首要创立一个Maven
项目,然后创立接口和完结类,目录总览如下,
UserDao.java
接口,
package com.idiot.dao;
public interface UserDao {
public void getUser();
}
Dao
的完结类,UserDaoImpl.java
,
package com.idiot.dao;
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据");
}
}
UserService
的接口,UserService.java
,
package com.idiot.service;
public interface UserService {
public void getUser();
}
Service
的完结类,UserServiceImpl.java
,
package com.idiot.service;
import com.idiot.dao.UserDao;
import com.idiot.dao.UserDaoImpl;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
测验一下,MyTest.java
,
import com.idiot.service.UserService;
import com.idiot.service.UserServiceImpl;
import org.junit.Test;
public class MyTest {
@Test
public void test(){
//用户实践调用的是事务层,Dao层他们不需求接触!
UserService service = new UserServiceImpl();
service.getUser();
}
}
这儿要运用 @Test
,需求导入 junit.jar
,
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
运转成果如下,
现在添加一个 Dao
的完结类,UserDaoOracleImpl.java
,
package com.idiot.dao;
public class UserDaoOracleImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle获取用户数据");
}
}
假如用户想去调用 Oracle
这个完结类,则咱们必须去源代码去修正代码,即在 service
完结类里边修正对应的完结,
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoOracleImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
再加一个 Mysql
的完结类也是相同的,UserDaoSqlserverImpl.java
,
package com.idiot.dao;
public class UserDaoSqlserverImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据");
}
}
现在咱们这个程序的代码少,修正起来是不费事的,但假设修正需求十分大 , 修正源码这种办法就根本不适用了, 每次变动都需求修正很多代码,这姿态的本钱代价是十分贵重的。
如何解决这样的问题?
咱们将运用一个 set
接口完结,使之产生革命性的改变!
UserServiceImpl.java
package com.idiot.service;
import com.idiot.dao.UserDao;
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 运用set完结
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
MyTest.java
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
//Mysql完结
service.setUserDao( new UserDaoSqlserverImpl() );
service.getUser();
//Oracle完结
service.setUserDao( new UserDaoOracleImpl() );
service.getUser();
}
与运用 set
前的代码进行比照,这现已产生了根本性的改变,以前一切东西都是由程序主动去进行操控创立 , 而运用了 set
注入之后,程序不再具有主动性,而是变成了被迫接受的方针,即把主动权交给了调用者,程序则只负责供给一个接口,
这种思维,从实质上解决了问题,咱们程序员不再去办理方针的创立,而是更多的去重视事务的完结,耦合性大大下降,这也便是IOC的原型!
创立方针办法
1. 运用无参结构创立方针(默许)
目录
User.java
package com.idiot.pojo;
public class User {
private String name;
public User() {
System.out.println("User无参结构");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("Name:"+ name );
}
}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.idiot.pojo.User">
<property name="name" value="Hello Spring!"/>
</bean>
</beans>
MyTest.java
import com.idiot.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
运转成果 此刻,将无参结构改成有参结构再运转,
public User(String name) {
System.out.println("User无参结构");
}
发现程序报错,没有办法进行初始化,Bean
初始化失败,
2. 运用有参结构创立方针
有参结构器,
public User(String name) {
this.name = name;
}
①下标赋值
<bean id="user" class="com.idiot.pojo.User">
<constructor-arg index="0" value="idiot"/>
</bean>
②类型赋值
假如有两个及以上的相同类型,就无法判别把值给谁了,因而不建议运用!
<bean id="user" class="com.idiot.pojo.User">
<constructor-arg type="java.lang.String" value="idiot.."/>
</bean>
③参数名赋值
<bean id="user" class="com.idiot.pojo.User">
<constructor-arg name="name" value="Idiot"/>
</bean>
总结:在装备文件加载的时分,容器中办理的方针就现已初始化了!
DI依靠注入
结构器注入
初始Spring的创立中已讲,忘了的话回头看一下。
Set注入
- 依靠注入:
set
注入,- 依靠:
bean
方针的创立依靠于容器, - 注入:
bean
方针中的一切特点由容器来注入,
- 依靠:
【环境搭建】
- 杂乱类型
- 实在测验方针
杂乱类型
Address.java
package com.idiot.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
假如在 Address
类中不添加 toString
办法,则会导致输出的不是 String
值,而是类似于这姿态的 com.idiot.pojo.Address@319b92f3
,
Student.java
package com.idiot.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobby;
private Map<String, String> card;
private Set<String> games;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", \naddress=" + address +
", \nbooks=" + Arrays.toString(books) +
", \nhobby=" + hobby +
", \ncard=" + card +
", \ngames=" + games +
", \nwife='" + wife + '\'' +
", \ninfo=" + info +
'}';
}
}
实在测验方针
1. 常量注入
<bean id="student" class="com.idiot.pojo.Student">
<property name="name" value="idiot"/>
</bean>
2. Bean注入
留意:这儿的值是一个引证,ref
,
<bean id="addr" class="com.idiot.pojo.Address">
<property name="address" value="浙江"/>
</bean>
<bean id="student" class="com.idiot.pojo.Student">
<property name="name" value="idiot"/>
<property name="address" ref="addr"/>
</bean>
3. 数组注入
<bean id="student" class="com.idiot.pojo.Student">
<property name="name" value="idiot"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>C++</value>
<value>Java</value>
<value>Python</value>
</array>
</property>
</bean>
4. List注入
<property name="hobby">
<list>
<value>sing</value>
<value>climb</value>
</list>
</property>
5. Map注入
<property name="card">
<map>
<entry key="中国电信" value="10000"/>
<entry key="中国移动" value="10086"/>
</map>
</property>
6. Set注入
<property name="games">
<set>
<value>堡垒之夜</value>
<value>皇室战役</value>
<value>王者荣耀</value>
</set>
</property>
7. Null注入
<property name="wife"><null/></property>
8. Properties注入
<property name="info">
<props>
<prop key="学号">123456</prop>
<prop key="性别">man</prop>
<prop key="名字">idiot</prop>
</props>
</property>
下面是完整的beans.xml
,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="addr" class="com.idiot.pojo.Address">
<property name="address" value="浙江"/>
</bean>
<bean id="student" class="com.idiot.pojo.Student">
<property name="name" value="idiot"/>
<property name="address" ref="addr"/>
<property name="books">
<array>
<value>C++</value>
<value>Java</value>
<value>Python</value>
</array>
</property>
<property name="hobby">
<list>
<value>sing</value>
<value>climb</value>
</list>
</property>
<property name="card">
<map>
<entry key="中国电信" value="10000"/>
<entry key="中国移动" value="10086"/>
</map>
</property>
<property name="games">
<set>
<value>堡垒之夜</value>
<value>皇室战役</value>
<value>王者荣耀</value>
</set>
</property>
<property name="wife"><null/></property>
<property name="info">
<props>
<prop key="学号">123456</prop>
<prop key="性别">man</prop>
<prop key="名字">idiot</prop>
</props>
</property>
</bean>
</beans>
以及测验MyTest.java
,
@Test
public void test01(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.toString());
}
运转成果
其他注入
P命名空间注入
需求在头文件中参加束缚文件xmlns:p="http://www.springframework.org/schema/p"
,且实体类中要存在无参结构器,
<!--p命名空间注入,能够直接注入特点的值:property-->
<bean id="userP" class="com.idiot.pojo.User" p:name="idiot" p:age="3"/>
MyTest.java
@Test
public void test02(){
ApplicationContext context = new ClassPathXmlApplicationContext("userBeans.xml");
User user = context.getBean("userP", User.class);
System.out.println(user);
}
C命名空间注入
雷同于P命名空间注入,
需求在头文件中参加束缚文件xmlns:c="http://www.springframework.org/schema/c"
,且实体类中要存在有参结构器,
<!--c命名空间注入,经过结构器注入:construct-args-->
<bean id="userC" class="com.idiot.pojo.User" c:age="3" c:name="idiot"/>
AOP
什么是AOP?
AOP
(Aspect Oriented Programming
)意为:面向切面编程,经过预编译办法和运转期动态署理完结程序功用的一致维护的一种技能。AOP
是 OOP
的延续,是软件开发中的一个热门,也是 Spring
结构中的一个重要内容,是函数式编程的一种衍生范型。运用 AOP
能够对事务逻辑的各个部分进行隔离,然后使得事务逻辑各部分之间的耦合度下降,提高程序的可重用性,一起提高了开发的功率。
AOP在Spring中的作用
供给声明式事务;允许用户自界说切面
- 横切重视点:跨越运用程序多个模块的办法或功用。与事务逻辑无关的,可是需求咱们重视的部分,便是横切重视点。如日志 , 安全 , 缓存 , 事务等等…
- 切面(
ASPECT
):横切重视点被模块化的特别方针。即它是一个类。 - 告诉(
Advice
):切面必需求完结的工作。即它是类中的一个办法。 - 方针(
Target
):被告诉方针。 - 署理(
Proxy
):向方针方针运用告诉之后创立的方针。 - 切入点(
PointCut
):切面告诉履行的“地点”的界说。 - 连接点(
JointPoint
):与切入点匹配的履行点。
SpringAOP
中,经过 Advice
界说横切逻辑,Spring
中支撑5种类型的 Advice
:
告诉类型 | 连接点 | 完结接口 |
---|---|---|
前置告诉 | 办法前 | org.springframework.aop.MethodBeforeAdvice |
后置告诉 | 办法后 | org.springframework.aop.AfterReturningAdvice |
盘绕告诉 | 办法前后 | org.aopalliance.intercept.MethodInterceptor |
反常抛出告诉 | 办法抛出反常 | org.springframework.aop.ThrowsAdvice |
引介告诉 | 类中添加新的办法特点 | org.springframework.aop.IntroductionInterceptor |
即 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完结
编写事务接口 UserService.java
,
package com.idiot.service;
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
再编写完结类 UserServiceImpl.java
,
package com.idiot.service;
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("添加用户");
}
@Override
public void delete() {
System.out.println("删去用户");
}
@Override
public void update() {
System.out.println("更新用户");
}
@Override
public void search() {
System.out.println("查询用户");
}
}
然后开始 AOP
环节,咱们编写两个告诉类 , 前置告诉 BeforeLog.java
, 后置告诉 AfterLog.java
,
BeforeLog.java
package com.idiot.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class BeforeLog implements MethodBeforeAdvice {
//method : 要履行的方针方针的办法
//args : 被调用的办法的参数
//target : 方针方针
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println( target.getClass().getName() + "的" + method.getName() + "办法被履行了");
}
}
AfterLog.java
package com.idiot.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
//method被调用的办法
//args 被调用的办法的方针的参数
//target 被调用的方针方针
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("履行了" + target.getClass().getName()
+"的"+method.getName()+"办法,"
+"返回值成果为:"+returnValue);
}
}
最终编写装备文件进行 Spring
中的注册,并完结 aop
切入完结,留意导入束缚,
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">
<!--注册bean-->
<bean id="userService" class="com.idiot.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.idiot.log.BeforeLog"/>
<bean id="afterLog" class="com.idiot.log.AfterLog"/>
<!--aop的装备-->
<aop:config>
<!--切入点 expression:表达式匹配要履行的办法-->
<aop:pointcut id="pointcut" expression="execution(* com.idiot.service.UserServiceImpl.*(..))"/>
<!--履行盘绕; advice-ref履行办法 . pointcut-ref切入点-->
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
expression
是一个表达式,其间 expression="execution()"
这是固定的,execution()
的括号里填写的参数是要履行的方位,
这是如何判别的呢?
大概是:修饰词 -> 返回值 -> 类名 -> 办法名 -> 参数值,
* com.idiot.service.UserServiceImpl.*(..)
,第一个*
表明类名前面能够是恣意的修饰词和返回值,第二个*
则表明恣意的办法名,..
表明恣意几个参数,
测验 MyTest.java
,
import com.idiot.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//留意:动态署理署理的是接口
UserService userService = context.getBean("userService",UserService.class);
userService.search();
}
}
Spring
的 Aop
便是将公共的事务 (日志,安全等) 和范畴事务结合起来,当履行范畴事务时,将会把公共事务加进来,完结公共事务的重复运用 ,范畴事务更朴实,程序猿专心范畴事务,其实质仍是动态署理,
法二:自界说类完结
方针事务类不变依旧是 userServiceImpl.java
,
- 自界说编写切入类
DiyPointcut.java
,
package com.idiot.diy;
public class DiyPointcut {
public void before(){
System.out.println("---------办法履行前---------");
}
public void after(){
System.out.println("---------办法履行后---------");
}
}
- 编写装备文件
applicationContext.xml
,
<!--注册bean-->
<bean id="userService" class="com.idiot.service.UserServiceImpl"/>
<bean id="diy" class="com.idiot.diy.DiyPointcut"/>
<!--aop的装备-->
<aop:config>
<!--运用AOP的标签完结-->
<aop:aspect ref="diy">
<aop:pointcut id="diyPointcut" expression="execution(* com.idiot.service.UserService.*(..))"/>
<aop:before pointcut-ref="diyPointcut" method="before"/>
<aop:after pointcut-ref="diyPointcut" method="after"/>
</aop:aspect>
</aop:config>
- 测验
MyTest.java
,
import com.idiot.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//留意:动态署理署理的是接口
UserService userService = context.getBean("userService",UserService.class);
userService.search();
}
}
法三:运用注解完结
- 编写一个注解完结的自界说类
AnnotationPointcut.java
,
package com.idiot.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.idiot.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------办法履行前---------");
}
@After("execution(* com.idiot.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------办法履行后---------");
}
@Around("execution(* com.idiot.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("盘绕前");
//履行方针办法proceed
Object proceed = jp.proceed();
System.out.println("盘绕后");
}
}
- 在
Spring
装备文件中注册bean
,并添加支撑注解的装备,
<bean id="annotationPointcut" class="com.idiot.diy.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy
阐明:
经过 aop
命名空间的 <aop:aspectj-autoproxy />
声明主动为 Spring
容器中那些装备 @aspect
切面的 bean
创立署理,织入切面,
当然,Spring
在内部依旧选用 AnnotationAwareAspectJAutoProxyCreator
进行主动署理的创立工作,但具体完结的细节现已被 <aop:aspectj-autoproxy />
隐藏起来了,
<aop:aspectj-autoproxy/>
有一个proxy-target-class
特点,默许为 false
,表明运用 jdk 动态署理织入增强,
当配为 <aop:aspectj-autoproxy poxy-target-class="true"/>
时,表明运用 CGLib 动态署理技能织入增强,
不过即使 proxy-target-class
设置为 false
,假如方针类没有声明接口,则 Spring
将主动运用CGLib动态署理。
整合Mybatis
回忆Mybatis
先是导入依靠包,装备库房,一起不要忘记装备 Maven
静态资源过滤,
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>Spring</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-10-mybatis</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- aspectJ AOP 织入器 -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!--装备Maven静态资源过滤问题-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
编写实体类 User.java
,
package com.idiot.pojo;
import lombok.Data;
@Data
public class User {
private int id; //id
private String name; //名字
private String pwd; //密码
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
再编写接口 UserMapper.java
及其映射文件 UserMapper.xml
,
UserMapper.java
package com.idiot.mapper;
import com.idiot.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.idiot.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from user
</select>
</mapper>
紧接着编写中心装备文件 mybatis-config.xml
以及外部装备文件 db.properties
,
mybatis-config.xml
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--引进外部装备文件-->
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="pwd" value="123456"/>
</properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.idiot.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${pwd}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.idiot.mapper.UserMapper"/>
</mappers>
</configuration>
db.properties
driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3307/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
最终进行测验,编写测验类 MyTest.java
,这儿没有像之前那样特意的去编写工具类了,然是直接在测验类中进行 SqlSession
的一系列操作,
import com.idiot.mapper.UserMapper;
import com.idiot.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
@Test
public void selectUser() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectUser();
for (User user: userList){
System.out.println(user);
}
sqlSession.close();
}
}
MyBatis-Spring
什么是 MyBatis-Spring
?
MyBatis-Spring
便是协助你将 MyBatis
代码无缝地整合到 Spring
中。
MyBatis-Spring
需求以下版本:
MyBatis-Spring | MyBatis | Spring 结构 | Spring Batch | JDK |
---|---|---|---|---|
2.0 | 3.5+ | 5.0+ | 4.0+ | Java 8+ |
1.3 | 3.4+ | 3.2.2+ | 2.1+ | Java 6+ |
因而需求在 pom.xml
中参加以下代码:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
要和 Spring
一起运用 MyBatis
,需求在 Spring
运用上下文中界说至少两样东西:一个 SqlSessionFactory
和至少一个数据映射器类。
在 MyBatis-Spring
中,可运用 SqlSessionFactoryBean
来创立 SqlSessionFactory
。要装备这个工厂 bean
,只需求把下面代码放在 Spring
的 XML 装备文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
留意:SqlSessionFactory
需求一个 DataSource
(数据源),且是仅有的必要特点。这能够是恣意的 DataSource
,只需求和装备其它 Spring
数据库连接相同装备它就能够了。
在根底的 MyBatis
用法中,是经过 SqlSessionFactoryBuilder
来创立 SqlSessionFactory
的。而在 MyBatis-Spring
中,则运用 SqlSessionFactoryBean
来创立。
在 MyBatis
中,你能够运用 SqlSessionFactory
来创立 SqlSession
。一旦你取得一个 session
之后,你能够运用它来履行映射了的语句,提交或回滚连接,最终,当不再需求它的时分,你能够关闭 session
。
一个常用的特点是 configLocation
,它用来指定 MyBatis
的 XML 装备文件途径。它在需求修正 MyBatis
的根底装备十分有用。通常,根底装备指的是 < settings>
或 < typeAliases>
元素。
需求留意的是,这个装备文件并不需求是一个完整的 MyBatis
装备。切当地说,任何环境装备,数据源和 MyBatis
的事务办理器都会被疏忽。SqlSessionFactoryBean
会创立它自有的 MyBatis
环境装备(Environment
),并按要求设置自界说环境的值。
SqlSessionTemplate
是 MyBatis-Spring
的中心。作为 SqlSession
的一个完结,这意味着能够运用它无缝替代你代码中现已在运用的 SqlSession
。
模板(Template
)能够参与到 Spring
的事务办理中,并且由于其是线程安全的,能够供多个映射器类运用,你应该总是用 SqlSessionTemplate
来替换 MyBatis
默许的 DefaultSqlSession
完结。在同一运用程序中的不同类之间稠浊运用或许会引起数据一致性的问题。
能够运用 SqlSessionFactory
作为结构办法的参数来创立 SqlSessionTemplate
方针。
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
现在这个bean
就能够直接注入到Mapper bean
中,
package com.idiot.mapper;
import com.idiot.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//sqlSession不必咱们创立,Spring来办理
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
接下来注入 SqlSessionTemplate
:
<bean id="userMapper" class="com.idiot.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
整合一
- 引进
Spring
的装备文件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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
- 装备数据源替换
mybaits
的数据源,
<!--装备数据源:数据源有十分多,能够运用第三方的,也可使运用Spring的-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3307/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
- 装备
SqlSessionFactory
来相关MyBatis
,
<!--装备SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--相关Mybatis-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/idiot/mapper/*.xml"/>
</bean>
- 注册
sqlSessionTemplate
,相关sqlSessionFactory
,
<!--注册sqlSessionTemplate , 相关sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--运用结构器注入-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
- 添加
Mapper
接口的完结类UserMapperImpl.java
,私有化sqlSessionTemplate
,
package com.idiot.mapper;
import com.idiot.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper{
//sqlSession不必咱们自己创立了,Spring来办理
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
- 注册
bean
完结,
<bean id="userMapper" class="com.idiot.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
- 再来看看咱们
Mybatis
的装备文件,发现一切内容都能够被Spring
整合,
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.idiot.pojo"/>
</typeAliases>
</configuration>
- 测验,
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper mapper = (UserMapper) context.getBean("userMapper");
List<User> user = mapper.selectUser();
System.out.println(user);
}
整合二
mybatis-spring1.2.3
版以上的才有这个,
dao
继承 Support
类 , 直接运用 getSqlSession()
取得 , 然后直接注入 SqlSessionFactory
,比起办法一,不需求办理 SqlSessionTemplate
, 并且对事务的支撑愈加友好,可跟踪源码检查,
修正 UserMapperImpl.java
,
package com.idiot.mapper;
import com.idiot.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
public List<User> selectUser() {
UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
return mapper.selectUser();
}
}
修正 applicationContext.xml
中 bean
的装备,
<bean id="userMapper" class="com.idiot.mapper.UserMapperImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
测验,
总结 : 整合到 Spring
今后能够完全不要 mybatis
的装备文件,除了这些办法能够完结整合之外,咱们还能够运用注解来完结,
跋文
以上内容仅仅简略的有要点的描绘了 Spring
结构,要真实把握仍是需求自己持续深入学习的,谨记面向百度编程!