Spring

简介

官网:https://spring.io/

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core

官方下载地址:https://repo.spring.io/release/org/springframework/spring/

GitHub:https://github.com/spring-projects

Maven

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.12.RELEASE</version>
</dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.2.12.RELEASE</version>
</dependency>

优点

  • 开源的免费的框架
  • 轻量级、非入侵式的框架
  • 控制反转(IOC)、面向切面编程(AOP)
  • 支持事务处理,对框架整合的支持

组成

拓展

现代化Java开发

IOC(控制反转) 理论推导

与传统方式的区别

传统:

  1. UserDao 接口
  2. UserDaoImpl 实现类
  3. UserService 业务接口
  4. UserServiceImpl 业务实现类

之前的业务中,用户的需求可能会影响原来的代码,我们需要根据用户的需求去修改源代码,如果程序代码量非常大,修改一次的成本非常高!

com.yangtao.dao.UserDao.java

public interface UserDao {void getUser();
}

com.yangtao.dao.UserDaoImpl.java

public class UserDaoImpl implements UserDao{@Overridepublic void getUser() {System.out.println("默认获取用户的数据");}
}

com.yangtao.service.UserService.java

public interface UserService {void getUser();
}

com.yangtao.service.UserServiceImpl.java

public class UserServiceImpl implements UserService{private UserDao userDao = new UserDaoImpl();@Overridepublic void getUser() {userDao.getUser();}
}

测试类 MyTest.java

public class MyTest {@Testpublic void TestUserDaoImpl(){UserServiceImpl userService = new UserServiceImpl();userService.getUser();}
}

com.yangtao.service.UserService.java中增加set接口实现 IOC

public class UserServiceImpl implements UserService{//private UserDao userDao = new UserDaoOracleImpl();private UserDao userDao;//利用set进行动态实现值的注入public void setUserDao(UserDao userDao){this.userDao = userDao;}@Overridepublic void getUser() {userDao.getUser();}
}
  • 之前程序主动创建对象,控制权在程序上
  • 使用了set注入后,程序不在具有主动性,而是变成了被动的接受对象

在测试类中就可以自定义传入的对象

public class MyTest {//用户实际调用的是业务层@Testpublic void TestUserDaoImpl(){UserServiceImpl userService = new UserServiceImpl();userService.setUserDao(new UserDaoImpl());            //用户可以自定义传入的实现类userService.getUser();}}

这种思想本质上解决了问题,程序员再也不去用管理对象的创建。系统的耦合性大大降低,可以更加专注业务实现,这是IOC原型 。

IOC本质

控制反转 IOC是一种设计思想,DI(依赖注入)是实现 IOC的一种方法。没有 IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序员自己控制,控制反转后对象的创建转移给第三方,即获得依赖对象的方式反转了。

控制:谁来控制对象的创建,传统应用程序的对象是程序本身控制创建的,使用Spring后,对象由Spring创建

反转:程序本身不创建对象,而变成被动地接收对象

依赖注入:就是利用 set方法来进行注入的

总结:对象由 Spring 创建、管理、装配!

IOC 与 Spring

IOC 是 Spring 框架的核心内容,使用多种方式完美的实现了 IOC,可以使用 XML 配置,也可以使用注解,新版本的 Spring 也可以零配置实现 IOC。

Spring 容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从 IOC 容器中取出需要的对象。

采用 XML 方式配置 Bean 的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean 的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,七实现方法时依赖注入(Dependency Injection,DI)。

HelloSpring

  1. 新建实体类 com.yangtao.pojo.Hello.java
public class Hello {private String str;public String getStr() {return str;}public void setStr(String str) {this.str = str;}@Overridepublic String toString() {return "Hello{" +"str='" + str + '\'' +'}';}
}
  1. 资源目录下新建 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 使用Spring来创建对象,在Spring中这些都成为Bean类型 变量名 = new 类型();Hello hello = new Hello();bean = 对象   new Hello();--><bean id="hello" class="com.yangtao.pojo.Hello"> <!-- 新建一个对象 --><property name="str" value="Spring"/>      <!--设置类的属性--></bean></beans>
  1. 测试类 MyTest.java
public class MyTest {@Testpublic void TestHello(){//获取Spring的上下文对象ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");//我们的对象都在Spring中管理了,如果要使用,就直接去取出来就行了Hello hello = (Hello) context.getBean("hello");//小细节,getBean()方法的第二个参数,指定类后不用再进行类型强转//Hello hello = context.getBean("hello", Hello.class);System.out.println(hello.toString());}
}

IOC创建对象方式

测试Spring使用无参构造方法创建对象(默认)

  1. 新建实体类 com.yangtao.pojo.User.java,重写无参构造方法
public class User {private String name;public User() {System.out.println("调用了无参构造方法!");}public String getName() {return name;}public void setName(String name) {this.name = name;}public void show(){System.out.println("name = " + name);}}
  1. 资源目录下新建 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="user" class="com.yangtao.pojo.User"><property name="name" value="yangtao"/></bean></beans>
  1. 测试类 Test.java,在getBean()方法处打断点,通过debug可以发现创建对象时调用了无参构造方法
public class Test {@org.junit.Testpublic void TestUser(){//测试Spring使用无参构造参数ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");User user = (User) context.getBean("user");user.show();}
}


使用有参构造方法创建对象1

  1. 为实体类 com.yangtao.pojo.User.java 添加有参构造方法
public User(String name){this.name = name;
}
  1. 修改 beans.xml,通过index位置传递参数赋值
<bean id="user" class="com.yangtao.pojo.User"><constructor-arg index="0" value="yangtao"/>
</bean>

使用有参构造方法创建对象2

  1. 修改 beans.xml,为指定的参数类型赋值
<bean id="user" class="com.yangtao.pojo.User"><constructor-arg type="java.lang.String" value="yangtao"/>
</bean>

使用有参构造方法创建对象3

  1. 修改 beans.xml,通过参数名为参数赋值
<bean id="user" class="com.yangtao.pojo.User"><constructor-arg name="name" value="yangtao"/>
</bean>

注意:在配置文件加载的时候,容器中管理的对象就已经初始化了!

Spring 配置

别名

<!-- 如果添加了别名,那我们也可以通过别名获取对象 -->
<alias name="user" alias="userBean"/>

Bean 的配置

<!--id:bean的唯一标识符class:bean对象所对应的全限定名:包名 + 类名name:也是别名,且可以取多个,通过 , 或空格分开不同的别名scope:定义bean的作用域,可以设置为单利模式或者原型模式(决定从容器中get的对象是否是同一个)
-->
<bean id="user" class="com.yangtao.pojo.User" name="user2 user3"><constructor-arg name="name" value="yangtao"/>
</bean>

import

一般用于团队开发使用,可以将多个配置文件,导入合并为一个,如,新建 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="beans.xml"/><import resource="beans2.xml"/></beans>

依赖注入

构造器注入

详见IOC创建对象方式

Set方式注入

  • 依赖注入:Set 注入

    • 依赖:bean对象的创建依赖容器
    • 注入:bean对象中的所有属性,由容器来注入

【环境搭建】

  1. 创建被引用的类 com.yangtao.pojo.Address.java
public class Address {private String address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "Address{" +"address='" + address + '\'' +'}';}
}
  1. 创建复杂类 com.yangtao.pojo.Student.java,用于测试各种类型的注入方式
public class Student {private String name;private Address address;private String[] books;private List<String> hobbys;private Map<String, String> card;private Set<String> games;private String wife;        //设置空指针nullprivate 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> getHobbys() {return hobbys;}public void setHobbys(List<String> hobbys) {this.hobbys = hobbys;}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", address=" + address.toString() +", books=" + Arrays.toString(books) +", hobbys=" + hobbys +", card=" + card +", games=" + games +", wife='" + wife + '\'' +", info=" + info +'}';}
}
  1. 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="address" class="com.yangtao.pojo.Address"><property name="address" value="广东"/></bean><bean id="student" class="com.yangtao.pojo.Student"><!-- 基本数据类型注入 --><property name="name" value="yangtao"/><!-- 引用类型注入 --><property name="address" ref="address"/><!-- 数组类型注入 --><property name="books"><array><value>西游记</value><value>红楼梦</value><value>三国演义</value><value>水浒传</value></array></property><!-- List注入 --><property name="hobbys"><list><value>冲浪</value><value>搞钱</value></list></property><!-- Map注入 --><property name="card"><map><entry key="身份证" value="123456666666666666"/></map></property><!-- Set注入 --><property name="games"><set><value>LOL</value><value>DNF</value></set></property><!-- null空指针注入,注意区别空值注入(value="") --><property name="wife"><null/></property><!-- Properties注入 --><property name="info"><props><prop key="学号">2021001</prop><prop key="密码">123123</prop></props></property></bean></beans>
  1. 测试类 MyTest.java
public class MyTest {@Testpublic void TestStudent(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");Student student = (Student) context.getBean("student");System.out.println(student.toString());}}
  1. 测试结果

拓展方式注入

新建实体类 com.yangtao.pojo.User.java,注意:需要重写无参和有参的构造方法

public class User {private int id;private String name;public User(){}public User(int id, String name) {this.id = id;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +'}';}
}

新建 UserBeans.xml,导入命名空间

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
  • p-namespace:对应无参构造
  • c-namespace:对应有参构造

整体:

<?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"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"><!--p-namespace对应无参构造<bean id="User1" class="com.yangtao.pojo.User"><property name="id" value="001"/><property name="name" value="yangtao1"/></bean>--><bean id="User1" class="com.yangtao.pojo.User" p:id="001" p:name="yangtao1"/><!--c-namespace对应有参构造<bean id="User2" class="com.yangtao.pojo.User"><constructor-arg name="id" value="002"/><constructor-arg name="name" value="yangtao2"/></bean>--><bean id="User2" class="com.yangtao.pojo.User" c:id="002" c:name="yangtao2"/>
</beans>

测试类 MyTest.java

public class MyTest {@Testpublic void TestUser(){ApplicationContext context = new ClassPathXmlApplicationContext("UserBeans.xml");User user1 = (User) context.getBean("User1");System.out.println(user1.toString());User user2 = (User) context.getBean("User2");System.out.println(user2.toString());}}

运行结果:

Bean 的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

3中装配的方式

  1. 在XML中显式的配置
  2. 在Java中显示配置
  3. 隐式的自动装配 bean【重点】

byName自动装配

实体类 com.yangtao.pojo.Cat.java

public class Cat {public void shout(){System.out.println("miao~");}
}

com.yangtao.pojo.Dog.java

public class Dog {public void shout(){System.out.println("wang~");}
}

com.yangtao.pojo.People.java

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;}@Overridepublic String toString() {return "People{" +"cat=" + cat +", dog=" + dog +", name='" + name + '\'' +'}';}
}

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"><bean id="cat" class="com.yangtao.pojo.Cat"/><bean id="dog" class="com.yangtao.pojo.Dog"/><!--byName:会自动在容器上下文中查找和自己对象set方法后面的值相对应的beanid,如setCat就查找由于id为cat的bean,实现自动装配--><bean id="people" class="com.yangtao.pojo.People" autowire="byName">       <!-- 通过byName实现自动装配 --><property name="name" value="yangtao"/><!--原有方法:手动装配--><!--<property name="cat" ref="cat"/><property name="dog" ref="dog"/>--></bean>
</beans>

测试类 MyTest.java

public class MyTest {@Testpublic void Test(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");People people = (People) context.getBean("people");people.getCat().shout();people.getDog().shout();}}

运行结果:

小结:byName实现自动装配,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致

还有一种是通过 byType 实现自动装配,这种方式甚至可以不为bean设置id,但需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。

使用注解实现自动装配

使用注解条件:

  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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/></beans>

@Autowired 注解

直接在实体类的属性上或set方法上添加 @Autowired注解,使用该注解后还可以省略 set 方法(前提是自动装配的属性在IOC(Spring)容器中存在,且复合名字byName),即可实现自动装配!

...@Autowiredprivate Cat cat;@Autowiredprivate Dog dog;
...

扩展:

构造方法参数前有 @Nullable 注解,说明这个参数可以为null,如

public User(@Nullable String name){this.name = name;
}

还有一种实现方式是设置 @Autowired 注解的属性 required = false

如果自动装配的环境比较复杂(如有多个bean的id不同,class相同,此时通过 @Autowired 就无法实现自动装配),此时可以添加 @Qualifier(value=“XXX”)来指定唯一的bean对象,实现自动装配

...
@Autowired
@Qualifier(value="cat111")
private Cat cat;
...

@Resource 注解

Java的原生注解,可以和 @Autowired实现相同的效果,且先判断 bean 的id,再判断 bean 的类型,都不匹配才报错!

如果环境复杂,可以为注解添加属性 @Resource(name=“XXX”) 指定唯一的 bean

@Resource 和 @Autowired

  1. 都是用来自动装配的,都可以放在属性字段上
  2. @Autowired 通过 byType 方式实现,而且要求这个对象必须存在
  3. @Resource 默认通过 byName 的方式实现,如果没有,则通过 byType 实现,两者找不到就报错
  4. @Autowired 一般与@Qualifier注解一起使用,通过后者的 value 属性指定 bean,@Resource则是通过 name 属性

使用注解开发

前提

在Spring4之后,要使用注解开发,必须导入 aop 包,之前 Maven 中导入了 spring-webmvc 已经包含了这个包

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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/>        <!-- 开启注解支持 --></beans>

ApplicationContext.xml 中开启包扫描

<context:component-scan base-package="com.yangtao.pojo"/>

环境搭建

实体类 com.yangtao.pojo.User.java

public class User {public String name = "yangtao";
}

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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><context:annotation-config/></beans>

测试类 MyTest.java

public class MyTest {@Testpublic void TestUser(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");User user = (User) context.getBean("user");System.out.println(user.name);}}

@Component 注解

组件,添加到类上,说明这个类被Spring管理了,就是bean

在实体类 com.yangtao.pojo.User.java 上添加注解

//等价于 <bean id="user" class="com.yangtao.pojo.User"/>
@Component
public class User {public String name = "yangtao";
}

完成配置

@Value() 注解

属性注入,用于属性之上

@Value("yangtao")
public String name;     // 相当于ApplicationContext.xml中配置 <property name="name" value="yangtao"/>

@Component 衍生的注解

在 web 开发中,会按照 MVC 三层架构分层

  • dao 【 @Repository 】
@Repository
public class UserDao {}
  • service 【 @Service 】
@Service
public class UserService {}
  • controller 【 @Controller 】
@Controller
public class UserController {}

自动装配的注解(详见上一节 Bean的自动装配)

  • @Autowired
  • @Nullable
  • @Resoutce

@Score 注解

实体类上添加该注解可以定义 bean 的作用域,prototype(原型)、singleton(单例)

@Scope("singleton")
public class User {public String name;
}

小结

  • XML:更加万能,适用于任何场合,维护简单方便,一般用于管理 bean
  • 注解:不是自己类用不了,维护相对复杂,一般用于属性的注入

使用 Java 配置 Spring

不使用 xml 配置,全部交给 Java 来做,在 Spring4之后成为了一个核心功能

新建实体类 com.yangtao.pojo.User.java

@Component
public class User {@Value("yangtao")private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';}
}

配置类

com.yangtao.config.MyConfig.java

@Configuration  //这个也会被Spring托管,注册到容器中,加入注解后代表这个类是一个配置类,相当于 ApplicationContext.xml
@ComponentScan("com.yangtao.pojo")     //扫描,使这个包下的注解生效
@Import(MyConfig2.class)    //导入其他配置
public class MyConfig {//注册一个bean,相当于ApplicationContext.xml中的bean标签//方法的名字相当于 bean的id属性//返回值相当于 bean 的class属性@Beanpublic User getUser(){return new User();}}

com.yangtao.config.MyConfig2.java

@Configuration
public class MyConfig2 {}

测试类 MyTest.java

public class MyTest {@Testpublic void TestJavaConfig(){//如果完全使用了配置类方式,就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);User getUser = (User) context.getBean("getUser");System.out.println(getUser.getName());}}

测试结果:

代理模式

静态代理

角色分析:

  • 抽象角色:一般使用接口或者抽象类解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色后,做一些附属操作
  • 客户:访问代理对象的人

代码实现

租房接口 com.yangtao.demo01.Rent.java

public interface Rent {public void rent();
}

真实角色–房东实现租房接口,出租房子 com.yangtao.demo01.Host.java

public class Host implements Rent {@Overridepublic void rent() {System.out.println("房东要出租房子!");}
}

代理角色–中介实现租房接口,帮房东出租房子,并有一些附属操作 com.yangtao.demo01.Proxy.java

public class Proxy implements Rent {private Host host;public Proxy(){}public Proxy(Host host) {this.host = host;}@Overridepublic void rent() {seeHouse();host.rent();hetong();fare();}//房东不能做,中介能做的事public void seeHouse(){System.out.println("中介带你看房!");}public void fare(){System.out.println("收中介费");}public void hetong(){System.out.println("签租借合同");}
}

真实角色–客户,想要租房子,找中介,传递想要租的房子 com.yangtao.demo01.Client.java

public class Client {public static void main(String[] args) {//房东要租房子Host host = new Host();//代理,中介帮房东租房子,代理角色一般有一些附属操作Proxy proxy = new Proxy(host);//客户不用面对房东,直接找中介租房proxy.rent();}
}

运行结果:

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不能关注一些公共的业务
  • 公共业务就交给了代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实的角色就会产生一个代理角色,代码量翻倍,效率变低

代理模式再理解


实例:通过代理实现对用户的增删查改

接口 com.yangtao.demo02.UserService.java

public interface UserService {public void add();public void delete();public void query();public void update();
}

实现类 com.yangtao.demo02.UserServiceImpl.java

public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("增加用户");}@Overridepublic void delete() {System.out.println("删除用户");}@Overridepublic void query() {System.out.println("查找用户");}@Overridepublic void update() {System.out.println("修改用户");}
}

代理类 com.yangtao.demo02.UserServiceProxy.java

public class UserServiceProxy {private UserServiceImpl userService;public void setUserService(UserServiceImpl userService){this.userService = userService;}public void add() {log("add");userService.add();}public void delete() {log("delete");userService.delete();}public void query() {log("query");userService.query();}public void update() {log("update");userService.update();}//日志输出方法public void log(String msg){System.out.println("【log】 " + msg + " 方法");}
}

用户类,增删查改 com.yangtao.demo02.Client.java

public class Client {public static void main(String[] args) {UserServiceImpl userService = new UserServiceImpl();UserServiceProxy userServiceProxy = new UserServiceProxy();userServiceProxy.setUserService(userService);userServiceProxy.delete();userServiceProxy.query();}
}

测试结果:

动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不需要我们编写代码
  • 动态代理分为:基于接口的动态代理(JDK动态代理)、基于类的动态代理(cglib)、Java字节码实现(javasist)

JDK动态代理,需要了解两个类:

  1. Proxy:创建动态代理类的实例提供了静态方法,也是所有动态代理类的父类的方法创建
static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
//返回指定的接口,将方法调用指定的调用处理程序的代理类的一个实例。
  1. InvocationHandler:通过一个代理实例零调用处理程序实现的接口
Object invoke(Object proxy, 方法 method, Object[] args)
//在代理实例上处理方法调用,并返回结果。

创建一个生成代理的工具类 com.yangtao.demo04.ProxyInvocationHandler.java

public class ProxyInvocationHandler implements InvocationHandler {//被代理的接口private Object target;public void setTarget(Object target) {this.target = target;}//生成得到代理类,固定代码,只需要修改代理类的接口public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);}//处理代理实例,并返回结果@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//动态代理的本质就是使用反射机制实现Object result = method.invoke(target, args);return result;}}

租房接口 com.yangtao.demo04.Rent.java

public interface Rent {public void rent();
}

房东类 com.yangtao.demo04.Host.java

public class Host implements Rent {@Overridepublic void rent() {System.out.println("房东要出租房子!");}
}

客户类 com.yangtao.demo04.Client.java

public class Client {public static void main(String[] args) {//真实角色Host host = new Host();//生成代理类ProxyInvocationHandler pih = new ProxyInvocationHandler();//通过调用程序处理角色来处理调用的接口对象pih.setTarget(host);//获得代理类(动态生成)Rent proxy = (Rent) pih.getProxy();//代理执行方法proxy.rent();}
}

测试结果:

小结:

  1. 可以使真实角色的操作更加纯粹!不用关注一些公共的业务
  2. 公共业务交给了代理角色,实现了业务的分工
  3. 公共业务发生扩展的时候,方便集中管理
  4. 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  5. 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

AOP

概念

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务罗技的各个部分进行隔离,从而使得业务罗技各部分之间的耦合性降低,提高程序的可重用性,同时提高了开发效率。

AOP在Spring中的作用

提供声明式事务,允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即,与我们业务罗技无关的,但是我们需要关注的部分,就是横切关注点,如:日志、安全、缓存、石凳等…
  • 切面(ASPECT):横切关注点,被模块化的特殊对象,即它是一个类
  • 通知(Advice):切面必须要完成的工作,即它是类中的一个方法
  • 目标(Target):被通知对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 切入点(PointCut):切面通知执行的 “地点” 的定义
  • 连接点(JointPoint):与切入点匹配的执行点


SpringAOP中,通过Advice定义横切逻辑,Spring中支持5中类型的Advice

即AOP在不改变原有代码的情况下,去增加新的功能。

使用 Spring API 接口实现 AOP【主要是SpringAPI接口实现】

使用AOP织入,需要导入一个依赖包

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

配置 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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><bean id="userService" class="com.yangtao.service.UserServiceImpl"/><bean id="log" class="com.yangtao.log.Log"/><bean id="afterLog" class="com.yangtao.log.AfterLog"/><!-- 使用原生Spring API接口 --><!-- 配置AOP:需要导入AOP的约束 --><aop:config><!-- 切入点:  execution(需要执行的位置 修饰词 返回值 列名 方法名 参数) --><aop:pointcut id="pointcut" expression="execution(* com.yangtao.service.UserServiceImpl.*(..))"/><!-- 执行环绕增加 --><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config>
</beans>

接口 com.yangtao.service.UserService.java

public interface UserService {public void add();public void delete();public void update();public void query();
}

实现类 com.yangtao.service.UserServiceImpl.java

public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("增加了一个用户");}@Overridepublic void delete() {System.out.println("删除了一个用户");}@Overridepublic void update() {System.out.println("更新了一个用户");}@Overridepublic void query() {System.out.println("查询了一个用户");}
}

日志的两个类 com.yangtao.log.Log.java

public class Log implements MethodBeforeAdvice { //实现MethodBeforeAdvice 接口,执行方法前会执行该类的方法//method:要执行的目标对象的方法//objects:参数//o:目标对象@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println(o.getClass().getName() + " 的 " + method.getName() + " 方法被执行了!");}
}

com.yangtao.log.AfterLog.java

public class AfterLog implements AfterReturningAdvice {  //实现AfterReturningAdvice 接口,执行方法后会执行该类的方法//o:返回值@Overridepublic void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {System.out.println("执行了 " + method.getName() + " 方法,返回结果为:" + 0);}
}

测试类 MyTest.java

public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");//注意动态代理返回的是一个接口UserService userService = (UserService) context.getBean("userService");userService.add();}
}

运行结果:

自定义类实现 AOP【主要是切面定义】

新建切面类 com.yangtao.diy.DiyPointCut.java

public class DiyPointCut {public void before(){System.out.println("=====方法执行前=====");}public void after(){System.out.println("=====方法执行后=====");}}

修改 ApplicationContext.xml

<aop:config><!-- 自定义切面,ref引用类 --><aop:aspect ref="diy"><!-- 切入点 --><aop:pointcut id="point" expression="execution(* com.yangtao.service.UserServiceImpl.*(..))"/><!-- 通知 --><aop:before method="before" pointcut-ref="point"/><aop:after method="after" pointcut-ref="point"/></aop:aspect>
</aop:config>

使用注解实现 AOP

com.yangtao.diy.AnnotationPointCut.java

@Component
@Aspect //标注这是一个切面类
public class AnnotationPorinCut {@Before("execution(* com.yangtao.service.UserServiceImpl.*(..))")   //注意不要导到junit的包,参数指定切入点public void before(){System.out.println("=====方法执行前=====");}@After("execution(* com.yangtao.service.UserServiceImpl.*(..))")public void after(){System.out.println("=====方法执行后=====");}//环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点@Around("execution(* com.yangtao.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint pj) throws Throwable {System.out.println("环绕前");Signature signature = pj.getSignature();    //获取签名,即执行中的方法System.out.println(signature);Object proceed = pj.proceed();  //执行方法System.out.println("环绕后");}}

配置 ApplicationContext.xml

<!-- 3. 使用注解实现AOP -->
<!-- 开启注解的支持  两种实现:JDK(默认proxy-target-class="true") cglib(false) -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.yangtao.*"/>

整合 MyBatis

步骤总览

  • 导入相关的包 junit、mybatis、mysql、spring相关、aop织入、mybatis-spring
  • 编写配置文件
  • 测试

回忆 MyBatis

  • 编写实体类
  • 编写核心配置文件
  • 编写接口
  • 编写Mapper.xml
  • 测试

MyBatis-Spring

MyBatis-Spring会帮助我们将MyBatis代码无缝的整合到Spring中。它将允许MyBatis参与到Spring的事务管理中,创建映射器mapper和SqlSession并注入到bean中,以及将MyBatis的异常转换为Spring的DataAccessException。最终,可以做到应用代码不依赖于MyBatis,Spring或MyBatis-Spring。

  • 编写数据源配置
  • SqlSessionFactory
  • SqlSessionTemplate
  • 给接口加实现类【操作原mybatis中的内容】并注入到Spring中
  • 测试使用

案例1(基于SqlSessionTemplate)

新建用于测试的数据库、数据表并插入数据

create database mybatis;use mybatis;
create table user(id int(20) not null,name varchar(30) default null,pwd varchar(30) default null,primary key(id)
)engine=innodb default charset=utf8;insert into user(id,name,pwd)values(1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456');

导入需要使用的包以及配置静态资源导出

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.12.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.12.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency>
</dependencies>
<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources>
</build>

创建实体类 com.yangtao.pojo.User.java

@Data
public class User {private int id;private String name;private String pwd;
}

接口 com.yangtao.dao.UserMapper.java

public interface UserMapper {public List<User> selectUser();
}

com.yangtao.dao.UserMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yangtao.dao.UserMapper"><select id="selectUser" resultType="user">select * from mybatis.user;</select></mapper>

编写配置文件

mybatis-config.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases><typeAlias type="com.yangtao.pojo.User" alias="user"/></typeAliases>
</configuration>

spring-dao.xml

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- DataSource:使用Spring的数据源替换MyBatis的配置 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;userUnicode=true&amp;characterEncoding=UTF-8"/><property name="username" value="root"/><property name="password" value="root"/></bean><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/yangtao/dao/*.xml"/></bean><bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg index="0" ref="sqlSessionFactory"/></bean></beans>

ApplicationContext.xml

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="spring-dao.xml"/>
<!--    <import resource="spring-mvc.xml"/>--><bean id="userMapperImpl" class="com.yangtao.dao.UserMapperImpl"><property name="sqlSessionTemplate" ref="sqlSessionTemplate"/></bean></beans>

给接口加实现类【操作原mybatis中的内容】com.yangtao.dao.UserMapperImpl.java

public class UserMapperImpl implements UserMapper {//SqlSession执行的操作将被SqlSessionTemplate代替private SqlSessionTemplate sqlSessionTemplate;public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {this.sqlSessionTemplate = sqlSessionTemplate;}@Overridepublic List<User> selectUser() {UserMapper mapper = sqlSessionTemplate.getMapper(UserMapper.class);return mapper.selectUser();}
}

测试类 MyTest.java

public class MyTest {@Testpublic void test(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");UserMapper userMapperImpl = context.getBean("userMapperImpl", UserMapper.class);List<User> users = userMapperImpl.selectUser();for (User user : users) {System.out.println(user);}}
}

测试结果:

案例2(基于SqlSessionDaoSupport)

新建实现类 com.yangtao.dao.UserMapperImpl2.java

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {@Overridepublic List<User> selectUser() {UserMapper mapper = getSqlSession().getMapper(UserMapper.class);return mapper.selectUser();}
}

将其注册到 ApplicationContext.xml

<bean id="userMapperImpl2" class="com.yangtao.dao.UserMapperImpl2"><property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

测试类 MyTest.java

@Test
public void test2(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");UserMapper userMapperImpl2 = context.getBean("userMapperImpl2", UserMapper.class);List<User> users = userMapperImpl2.selectUser();for (User user : users) {System.out.println(user);}
}

声明式事务

回顾事务

  • 把一组业务当成一个业务来做,要么都成功,要么都失败
  • 事务在项目开发中,涉及到数据的一致性问题
  • 确保数据的完整性和一致性

事务 ACID 原则:

  • 原子性
  • 一致性
  • 隔离性
  • 持久性

Spring中的事务管理

  • 声明式事务(AOP)
  • 编程式事务

案例

项目导包

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.12.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.12.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version></dependency><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.18</version></dependency></dependencies><build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources>
</build>

实体类 com.yangtao.pojo.User.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String name;private String pwd;
}

接口 com.yangtao.dao.UserMapper.java 中定义3个方法

public interface UserMapper {public List<User> selectUser();//添加一个用户public int addUser(User user);//删除一个用户public int deleteUser(int id);}

UserMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yangtao.dao.UserMapper"><select id="selectUser" resultType="user">select * from mybatis.user;</select><insert id="addUser" parameterType="user">insert into mybatis.user (id, name, pwd) VALUES (#{id},#{name},#{pwd});</insert><delete id="deleteUser" parameterType="int">delete from mybatis.user where id=#{id};</delete></mapper>

配置文件 mybatis-config.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><typeAliases><typeAlias type="com.yangtao.pojo.User" alias="user"/></typeAliases></configuration>

spring-dao.xml 配置事务

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!-- DataSource:使用Spring的数据源替换MyBatis的配置 --><bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;userUnicode=true&amp;characterEncoding=UTF-8"/><property name="username" value="root"/><property name="password" value="root"/></bean><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/yangtao/dao/*.xml"/></bean><bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"><constructor-arg index="0" ref="sqlSessionFactory"/></bean></beans>

ApplicationContext.xml

<?xml version="1.0" encoding="UTF8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><import resource="spring-dao.xml"/><bean id="userMapperImpl" class="com.yangtao.dao.UserMapperImpl"><property name="sqlSessionTemplate" ref="sqlSessionTemplate"/></bean></beans>

实现类 com.yangtao.UserMapperImpl.java

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {// 在查询用户方法中加入了新增用户和删除用户的方法,模仿事务执行@Overridepublic List<User> selectUser() {User user = new User(5, "小王", "123123");UserMapper mapper = getSqlSession().getMapper(UserMapper.class);mapper.addUser(user);mapper.deleteUser(5);return mapper.selectUser();}@Overridepublic int addUser(User user) {UserMapper mapper = getSqlSession().getMapper(UserMapper.class);return mapper.addUser(user);}@Overridepublic int deleteUser(int id) {UserMapper mapper = getSqlSession().getMapper(UserMapper.class);return mapper.deleteUser(id);}
}

假设我们将整个查询方法当成一个事务,而执行这个方法的过程中,新增用户成功了,但是删除出错了,那么这个方法成功了一半,这与事务的原子性不符合,因此我们需要在配置文件 spring-dao.xml 中配置事务

<!-- 配置声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><constructor-arg ref="dataSource" />
</bean><!-- 结合AOP实现事务的织入 -->
<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager"><!--给哪些方法配置事务--><!-- 配置事务的传播特性 --><tx:attributes><tx:method name="add" propagation="REQUIRED"/><tx:method name="delete" propagation="REQUIRED"/><tx:method name="update" propagation="REQUIRED"/><tx:method name="query" read-only="true"/><tx:method name="*" propagation="REQUIRED"/></tx:attributes>
</tx:advice><!-- 配置事务切入 -->
<aop:config><aop:pointcut id="txPointCut" expression="execution(* com.yangtao.dao.*.*(..))"/><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>

测试 MyTest.java

public class MyTest {@Testpublic void test(){ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");UserMapper userMapperImpl = context.getBean("userMapperImpl", UserMapper.class);List<User> users = userMapperImpl.selectUser();for (User user : users) {System.out.println(user);}}}

Spring个人笔记相关推荐

  1. 【Spring学习笔记-MVC-13.2】Spring MVC之多文件上传

    作者:ssslinppp       1. 摘要 前篇文章讲解了单文件上传<[Spring学习笔记-MVC-13]Spring MVC之文件上传>http://www.cnblogs.co ...

  2. Spring读书笔记——bean创建(下)

    有关Spring加载bean系列,今天这是最后一篇了,主要接上篇对于从Spring容器中获取Bean的一些细节实现的补充. <Spring读书笔记--bean加载>--Spring如何加载 ...

  3. Spring学习笔记(三) AOP_annotation,AOP_XML

    在学习课程以前,听说AOP有种很神秘的感觉,好像很好深的技术.其实原理很简单,使用动态代理的方式给程序增加逻辑.与此相似的有struts2中的filter拦截器. 再讲AOP之前先把需求说一下: 同S ...

  4. spring 事务笔记(四)

    spring 事务笔记(四) 文章目录 spring 事务笔记(四) spring 事务原理简述 声明式事务 1. 注解方式 配置事务管理器 开启事务并使用 2.xml配置方式 配置事务管理器 配置事 ...

  5. (转) Spring读书笔记-----Spring的Bean之配置依赖

    前一篇博客介绍了Spring中的Bean的基本概念和作用域(Spring读书笔记-----Spring的Bean之Bean的基本概念 ),现在介绍Spring Bean的基本配置. 从开始我们知道Ja ...

  6. spring学习笔记06-spring整合junit(出现的问题,解决的思路)

    spring学习笔记06-spring整合junit(出现的问题,解决的思路) 文章目录 spring学习笔记06-spring整合junit(出现的问题,解决的思路) 3.1测试类中的问题和解决思路 ...

  7. spring学习笔记01-BeanFactory和ApplicationContext的区别

    spring学习笔记01-BeanFactory和ApplicationContext的区别 BeanFactory 和 ApplicationContext 的区别           BeanFa ...

  8. spring学习笔记02-spring-bean创建的细节问题

    spring学习笔记02-spring-bean创建的细节问题 三种创建Bean对象的方式 Bean的作用范围 Bean的生命周期 <?xml version="1.0" e ...

  9. spring学习笔记03-spring-DI-依赖注入详解(通过xml配置文件来配置依赖注入)

    spring学习笔记03-spring-DI-依赖注入详解 1.概念 2.构造函数注入 3.set方法注入 4.集合的注入 需要被注入的实体对象 package com.itheima.service ...

  10. Spring学习笔记:配置单数据源

    Spring学习笔记:配置单数据源 一.Spring Boot默认数据源类型 Springboot默认支持4种数据源类型,定义在 org.springframework.boot.autoconfig ...

最新文章

  1. 【机器学习入门到精通系列】粒子群优化算法
  2. Spring 框架 详解 (四)------IOC装配Bean(注解方式)
  3. EF Core:一统SQL和NoSQL数据库
  4. [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数
  5. 车刀 matlab,可转位车刀的结构
  6. 惠而浦扫地机器人充不进电_【今日关注】惠而浦扫地机器人怎么样?体验2个月之肺腑之言? | 智能扫地机器人评测...
  7. linux oracle异常处理,Oracle SQL 异常处理
  8. 【转】Python自动化测试 (一) Eclipse+Pydev 搭建开发环境
  9. Tensorflow:分类模型评估
  10. Hadoop HA集群部署
  11. Altium_Protel99SE的使用
  12. 三星android rom开发者,三星s10刷机包安卓10(极光AuroraROM 13.0)
  13. linux fedora14 u盘运行,通过U盘安装Fedora-14-i686-Live-Desktop
  14. 遗传算法原理,交叉、变异、适应度函数的设置
  15. WorldPress博客系统更换域名导致博客访问出错的解决方案
  16. PDF Reader XI 闪退+安装组件错误代码提示1935最完美最靠谱的解决方案
  17. HDU - 2859 Phalanx (DP)
  18. 那个炒币,8小时赚了一辆法拉利的女大学生,现在怎么样了?
  19. 什么叫工业4.0?这篇接地气的文章终于讲懂了!
  20. 如何快速搭建个人网站(服务器配置篇)

热门文章

  1. 编程课程学习_如果您想学习数据科学,请从以下编程课程之一开始
  2. Linux下poky编译2
  3. windows xp 算号原理
  4. iOS越狱开发环境搭建 theos
  5. CSS,给你点“颜色“看看
  6. Oracle:2、SQL基础
  7. wpf的path画三角形、四边形
  8. 下载安装Psychtoolbox详细教程【Windows10+Matlab R2020a】
  9. MAX232与MAX3232的区别
  10. 直播预告 | 硅步机器人携手Shadow Robot原厂技术大咖 深度解析遥操作系统