◆ Spring:春天 给软件行业带来了春天
◆ 2002,首次推出了Spring框架的雏形:interface21框架
◆ Spring框架即是以interface21框架为基础经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版
◆ Rod Johnson Spring Framework创始人,著名作者。 Rod在悉尼大学不仅获得了计算机学位,同时还获得了音乐学位。更令人吃惊的是在回到软件开发领域之前,他还获得了音乐学的博士学位。 有着相当丰富的C/C++技术背景的Rod早在1996年就开始了对Java服务器端技术的研究
◆“轮子理论”,也即“不要重复发明轮子”
◆ Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
◆ SSH :Struct2 + Spring + Hibernate(过时)
◆ SSM:SpringMVC + SPring +Mybatis(现在)
官网:https://spring.io/
官网Spring快速入门指南:https://spring.io/quickstart
官方学习指南(建议收藏):https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#spring-core
官网API:https://docs.spring.io/spring-framework/docs/current/javadoc-api/
官网Spring概述:https://docs.spring.io/spring-framework/docs/current/reference/html/overview.html#overview
官网项目下载:https://start.spring.io/
官方全部版本下载地址:http://repo.spring.io/release/org/springframework/spring
GitHub:https://github.com/spring-projects/spring-framework
后面学习需要的jar包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
◆ Spring是一个开源的免费的框架(容器)!
◆ Spring是一个轻量级的,非入侵式的框架
◆ 控制反转(IOC),面向切面编程(AOP)
◆ 支持事务的处理,对框架整合的支持!
总结:Spring就是一个轻量级的控制反转(IOC)和切面编程(AOP)的框架!
在spring以前的官网有这个介绍:现代化的java开发,说白了就是基于spring开发!
后面需要学习的内容:
◆ Spring Boot
◎ 一个快速开发的脚手架。
◎ 基于SpringBoot可以快速的开发单个微服务。
◎ 约定大于配置!
◆ Spring Cloud
◎ SpringCloud是基于SpringBoot实现的。
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!
弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!
在Java开发中,IOC 意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。理解好IOC的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
● 谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建以及外部资源获取(不只是对象包括比如文件等)。
● 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象:由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转,依赖对象的获取被反转了。
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;
有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IoC对编程实现由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下:
● 谁依赖于谁:当然是应用程序依赖于IoC容器;
●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
● 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
● 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
原来的实现方式
1.UserDao接口
package com.cy.dao;
/**接口*/
public interface UserDao {
void getUser();
}
2.UserDaoImpl实现类
package com.cy.dao;
public class UserDaoMysqlImpl implements UserDao{
public void getUser(){
System.out.println("Mysql获取用户信息");
}
}
3.UserService业务接口
package com.cy.service;
//业务层
public interface UserService {
void getUser();
}
4.UserServiceImpl实现类
package com.cy.service;
import com.cy.dao.UserDao;
import com.cy.dao.UserDaoImpl;
import com.cy.dao.UserDaoMysqlImpl;
//业务层调Dao层
public class UserServiceImpl implements UserService{
//组合
private UserDao userDao = new UserDaoImpl();
public void getUser() {
userDao.getUser();
}
}
测试:
package com.cy.dao;
import com.cy.service.UserService;
import com.cy.service.UserServiceImpl;
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
增加需求,增加一个mysql的实现
5.UserDaoMysqlImpl实现类
public class UserDaoMysqlImpl implements UserDao{
public void getUser(){
System.out.println("Mysql获取用户信息");
}
}
修改业务层实现类
//业务层调Dao层
public class UserServiceImpl implements UserService{
//组合
private UserDao userDao = new UserDaoMysqlImpl();
public void getUser() {
userDao.getUser();
}
}
测试:
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
我们可以发现,成功换到了Mysql ,但是有弊端:我们增加了类,修改了原有的代码
如果现在客户想调用一个新的UserDaoOracleImpl 实现类
public class UserDaoOracleImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Oracle获取用户数据!");
}
}
如果要调用这个类,我们又要去业务层修改实现类
//业务层调Dao层
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoOracleImpl();
public void getUser() {
userDao.getUser();
}
}
我们可以发现这种方法特别麻烦,我们因为客户的需求去改变更的代码,这是肯定有问题的,行不通的!
如果想要改变,就需要每次更改UserServiceImpl
怎么解决这种问题?(解决掉用户?解决掉甲方?解决掉出问题的人?)
怎么让程序不动,让客户端自己去工作?(工厂模式)
修改业务实现类
若将UesrDao使用Set接口实现
//业务层调Dao层
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void getUser() {
userDao.getUser();
}
}
测试:
public class MyTest {
public static void main(String[] args) {
//用户实际调用的是业务层,dao层他们不需要接触!
UserService userService = new UserServiceImpl();
((UserServiceImpl)userService).setUserDao(new UserDaoMysqlImpl());
userService.getUser();
}
}
((UserServiceImpl)userService).setUserDao(new UserDaoOracleImpl());
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!
如果代码量十分大,修改一次的成本代价,成本十分昂贵!
我们使用一个Set接口实现,已经有了革命性的变化:
private UserDao userDao;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
思考:好处在哪里?(dao交给用户控制,程序员不用在修改原程序)
• 之前,程序通过new主动创建对象!控制权在程序猿手上
• 使用set注入后,程序不再具有主动性,而是变成了被动的接受对象!
• 这种思想,从本质上解决了问题,程序员不用再去管理对象的创建了,降低了耦合性!
• 使程序员,可以更加专注在业务的实现上!
• 这就是 IOC 的原型
控制反转loC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现loC的一种方法,也有人认为DI只是loC的另一种说法。没有loC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
loC是Spring框架的核心内容,使用多种方式完美的实现了loC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现loC。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从loc容器中取出需要的对象。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(xml或注解)并通过第三方去生产或获取特定对象的方式。在spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,DI)。
Hello 实体类
package com.cy.pojo;
public class Hello {
private String str;
//直接添加toString、get、set
}
applicationContext.xml文件
<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="hello" class="com.cy.pojo.Hello">
<property name="str" value="spring"/>
bean>
beans>
测试:
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//我们的对象现在都在spring中管理,我们要使用,直接去里面取出来
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
1.Hello 对象是谁创建的?(Hello 对象是由spring创建的)
2.Hello 对象的属性是怎么设置的?(Hello 对象的属性是由Spring容器设置的)
这个过程就叫控制反转:
● 控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后对象由Spring来创建的。
● 反转:程序本身不创建对象,而变成被动的接收对象。
● 依赖注入:就是利用set方法来进行注入的。
● IOC是一种编程思想,由主动的编程变成被动的接收,所谓的IOC,即对象由Spring来创建,管理,装配。
● 可以通过newClassPathXmlApplicationContext去浏览一下底层源码。
生活案例:相当于请客吃饭
原来的这套程序是:你写好菜单买好菜,客人来了自己把菜炒好 招待客人
现在的这套程序是:你告诉楼下餐厅,你要哪些菜,客人来的时候,餐厅把做好的菜,给你送上来
IOC:炒菜这件事情,不再由你自己来做,而是委托给了第三方:餐厅来做
打开刚才的spring-01-ioc
在resources中添加xml
applicationContext.xml
<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="mysqlImpl" class="com.cy.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="com.cy.dao.UserDaoOracleImpl"/>
<bean id="UserServiceImpl" class="com.cy.service.UserServiceImpl">
<property name="userDao" ref="mysqlImpl"/>
bean>
beans>
测试:
public class MyTest {
public static void main(String[] args) {
//获取ApplicationContext:拿到Spring的容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//容器在手,天下我有,需要什么就get什么!
UserServiceImpl userService= (UserServiceImpl) context.getBean("UserServiceImpl");
userService.getUser();
}
}
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC,一句话搞定:对象由Spring 来创建,管理,装配!
新建一个项目:spring-03-ioc2
package com.cy.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);
}
}
创建applicationContext.xml
<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.cy.pojo.User">
<property name="name" value="清风"/>
bean>
beans>
测试:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user= (User) context.getBean("user");
user.show();
}
}
public class User {
private String name;
public User(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+name);
}
}
<!--下标赋值-->
<bean id="user" class="com.cy.pojo.User">
<constructor-arg index="0" value="淡若清风"/>
</bean>
<bean id="user" class="com.cy.pojo.User">
<constructor-arg type="java.lang.String" value="qingfeng"/>
bean>
<bean id="user" class="com.cy.pojo.User">
<constructor-arg name="name" value="清风"/>
bean>
我们再创建一个User2实体类
package com.cy.pojo;
public class User2 {
private String name;
public User2(){
System.out.println("Uset2无参构造被创建了");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name="+name);
}
}
<bean id="user" class="com.cy.pojo.User">
<constructor-arg name="name" value="清风"/>
bean>
<bean id="user2" class="com.cy.pojo.User2">
bean>
运行测试结果:
对比他们是否相等
User user= (User) context.getBean("user");
User user2= (User) context.getBean("user");
System.out.println(user == user2);
小结:
Spring容器,就类似于婚介网站,想要什么类型的对象,直接给婚介说,它给你安排!
在获取spring的上下文对象( new ClassPathXmlApplicationContext(“beans.xml”); )时,spring容器中的所有的对象就已经被创建了。
<alias name="user" alias="userAlias"/>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user= (User) context.getBean("userNew");
user.show();
}
}
<bean id="user2" class="com.cy.pojo.User2" name="user3,user4 user5;user6">
<property name="name" value="淡若清风"/>
bean>
测试:
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//User2 user= (User2) context.getBean("user3");
User2 user= (User2) context.getBean("user4");
user.show();
}
}
import,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个
假设,现在项目中又多个人开发,这三个人负责不同的类开发,不同的类需要注册在不同的bean中,我们可以用import将所有人的beans.xml合并为一个总的!
● 张三1、李四2、王五3
● appliacationContext1.xml
● appliacationContext2.xml
● appliacationContext3.xml
合并(内容相同也会合并)
<import resource="applicationContext1.xml"/>
<import resource="applicationContext2.xml"/>
<import resource="applicationContext3.xml"/>
使用的时候,直接使用总的配置就可以了
●上面内容已经讲解
●依赖注入:Set注入
●依赖:bean对象的创建依赖于容器!
●注入:bean对象中的所有属性,由容器来注入!
【环境搭建】
1.复杂类型
package com.cy.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 + '\'' +
'}';
}
}
2.真实测试对象
package com.cy.pojo;
public class Student {
//普通属性value赋值,普通类ref赋值
private String name;
private Address address;
private String [] books;
private List<String> hobbies;
private Map<String, String> card;
private Set<String> games;
private String wife; //空指针
private Properties info;
//以及Getter与Setter方法
}
3.applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="address" class="com.cy.pojo.Address">
<property name="address" value="重庆"/>
bean>
<bean id="student" class="com.cy.pojo.Student">
<property name="name" value="清风"/>
<property name="address" ref="address"/>
<property name="books">
<array>
<value>红楼梦value>
<value>西游记value>
<value>水浒传value>
<value>三国演义value>
array>
property>
<property name="hobbies">
<list>
<value>听歌value>
<value>看电影value>
<value>敲代码value>
list>
property>
<property name="card">
<map>
<entry key="身份证" value="5000020210204656"/>
<entry key="手机号" value="6024106834891235"/>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>COCvalue>
<value>BOBvalue>
set>
property>
<property name="wife">
<null/>
property>
<property name="info">
<props>
<prop key="学号">1001prop>
<prop key="姓名">清风prop>
<prop key="username">1043051018prop>
<prop key="password">123456789prop>
props>
property>
bean>
beans>
4.测试
package com.cy.pojo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
/**运行结果:
* Student{
* name='清风',
* address=Address{address='重庆'},
* books=[红楼梦, 西游记, 水浒传, 三国演义],
* hobbies=[听歌, 看电影, 敲代码],
* card={
* 身份证=5000020210204656,
* 手机号=6024106834891235
* },
* games=[LOL, COC, BOB],
* wife='null',
* info={
* 学号=1001,
* password=123456789,
* 姓名=清风,
* username=1043051018
* }
* }
*/
}
}
创建User 实体类
package com.cy.pojo;
public class User {
private String name;
private int age;
public User(){}
public User(String name, int age) {
this.name = name;
this.age = age;
}
//自己导get/set/toString
}
p标签注入,须在beans中引入 xmlns:p=“http://www.springframework.org/schema/p”
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.cy.pojo.User" p:name="清风" p:age="18"/>
beans>
先在pom.xm导入junit包
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("Userapplicat.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
运行结果:
c标签注入,需在实体中增加有参构造方法,并引入 xmlns:c=“http://www.springframework.org/schema/c”
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.cy.pojo.User" p:name="清风" p:age="18"/>
<bean id="user2" class="com.cy.pojo.User" c:name="重庆" c:age="20"/>
beans>
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("Userapplicat.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
注意点:p命名和c命名空间不能直接使用,需要导入xml约束!
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
创建bean定义时,将创建用于创建实际实例的配方 该bean定义所定义的类的名称。 Bean定义是一个想法 配方很重要,因为它意味着像创建类一样,您可以创建许多对象 单个配方的实例。
仅管理一个singleton bean的一个共享实例,并且所有对bean的请求 一个或多个与该bean定义相匹配的ID会导致该特定bean Spring容器返回的实例。
换句话说,当您定义bean定义并将其范围限定为 单例,Spring IoC容器仅创建对象的一个实例 由该bean定义定义。 该单个实例存储在这样的缓存中 单例bean,以及该命名bean的所有后续请求和引用 返回缓存的对象。 下图显示了单例作用域的工作方式:
官方:
<bean id="accountService" class="com.something.DefaultAccountService"/>
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
参考自己的:
<bean id="user2" class="com.cy.pojo.User" c:name="重庆" c:age="20" scope="singleton"/>
Bean部署的非单一原型范围导致创建新的 每次对该特定bean发出请求时,该bean实例。 即豆 被注入到另一个bean中,或者您通过 getBean()对 容器。 通常,您应该对所有有状态Bean使用原型作用域,并且 无状态bean的单例作用域。
(一个数据访问对象 (DAO)通常不配置为原型,因为典型的DAO不能容纳 任何对话状态。 对我们来说,重用核心 单例图。)
以下示例将bean定义为XML原型:
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
原型模式:每次从容器中get的时候,都会产生一个新对象!
● 自动装配是spring满足bean依赖的一种方式
● Spring会在上下文中自动寻找,并自动给bean装配属性
◆ 在Spring中由三种装配方式:
1.在xml中显式配置
2.在java中显式配置
3.隐式的自动装配bean 【重要】
1.环境搭建
● 一个人有两个宠物,一只猫一只狗
创建3个类:
package com.cy.pojo;
public class Cat {
public void shout(){
System.out.println("喵喵喵~");
}
}
package com.cy.pojo;
public class Dog {
public void shout(){
System.out.println("汪汪汪~");
}
}
封装
package com.cy.pojo;
public class People {
private Cat cat;
private Dog dog;
private String name;
//自己加get、set、toString
}
applicationContext.xml
<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="cat" class="com.cy.pojo.Cat"/>
<bean id="dog" class="com.cy.pojo.Dog"/>
<bean id="people" class="com.cy.pojo.People">
<constructor-arg name="name" value="淡若清风"/>
<constructor-arg name="dog" value="dog"/>
<constructor-arg name="cat" value="cat"/>
bean>
beans>
测试:
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext( "applicationContext.xml");
People people = context.getBean( "people", People.class);
people.getDog().shout();
people.getCat().shout();
}
byName:会在容器上下文中查找,和自己对象set方法后面的值相对应的beanid
● byName弊端:类型必须唯一
<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="cat" class="com.cy.pojo.Cat"/>
<bean id="dog" class="com.cy.pojo.Dog"/>
<bean id="people" class="com.cy.pojo.People" autowire="byName">
<property name="name" value="清风"/>
bean>
beans>
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean
● byType:主要set名字和id相同就能装配
● 不命名也能装配
<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="cat111" class="com.cy.pojo.Cat"/>
<bean id="dog2222" class="com.cy.pojo.Dog"/>
<bean id="people" class="com.cy.pojo.People" autowire="byType">
<property name="name" value="清风"/>
bean>
beans>
小结:
byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
注释在配置Spring方面比XML更好吗?
基于注释的配置的引入提出了这样一个问题: 这种方法比XML“更好”。 简短的答案是“取决于情况”。 长答案是 每种方法都有其优点和缺点,通常,这取决于开发人员 确定哪种策略更适合他们。 由于定义的方式,注释 在声明中提供了很多背景信息,从而使内容更简短 组态。 但是,XML擅长连接组件而不接触其源代码 编码或重新编译它们。 一些开发人员更喜欢布线靠近源头 而另一些人则认为带注释的类不再是POJO,而且, 配置变得分散,难以控制。
注意:注释注入在XML注入之前执行。 因此,XML配置 覆盖通过两种方法连接的属性的注释。
1.导入约束:context约束
2.配置注解的支持:
【重要】
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
beans>
对刚刚的案例进行优化:
导入约束
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean id="cat" class="com.cy.pojo.Cat"/>
<bean id="dog111" class="com.cy.pojo.Dog"/>
<bean id="people" class="com.cy.pojo.People"/>
beans>
public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
//自己导入get/toString
}
测试:
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
People people=context.getBean("people",People.class);
people.getCat().shout();
people.getDog().shout();
}
小结:
直接在属性上使用即可!也可以在set方式上使用
使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName
Autowired默认优先按类型匹配,如果多个bean类型相同,就会再按名称匹配
Autowired注解相当于智能识别,,当注入在loC容器中该类型只有一个时。就通过byType进行装配当注入容器,存在多个同一类型的对象时,就是根据byName进行装配
@Nullable 字段标记了这个注解,说明这个字段可以为null;
public @interface Autowired{
boolean required() default true;
}
测试代码:
如果显示定义了Autowired的required属性为alse,说明这个对象可以为null,否则不允许为空
public class People {
//如果定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private Cat cat;
@Autowired
private Dog dog;
private String name;
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value = “xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
public class People {
@Autowired
@Qualifier(value = "cat111")
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
private String name;
}
@Resource注解,不指定name值,先去判断byName和byType,有一个能注入即成功
public class People {
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
@Resource和@Autowired的区别
●都是用来自动装配的,都可以放在属性字段上
●@Autowired通过byType的方式实现,而且必须要求这个对象存在!
●@Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!
● 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byName的方式实现。
@Autowired 默认优先按类型匹配,如果多个bean类型相同,就会再按名称匹配
@Nullable 字段标记了这个注解,说明这个字段可以为null;
@Qualifier 可以通过@Qualifier(value = “xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
@Resource 注解,不指定name值,先去判断byName和byType,有一个能注入即成功
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.cy"/>
</beans>
//等价于
//@Component 组件
@Component
public class User {
public String name = "清风";
}
测试:
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
}
@Component
public class User {
//@Value("qf") 相当于
@Value("qf")
public String name;
}
加上set方法
@Component
public class User {
public String name;
@Value("qf")
public void setName(String name) {
this.name = name;
}
}
@Componet有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
dao层 【@Repository】
service层 【@Service】
controller层 【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
XML 与 注解
XML 与 注解最佳实践
<context:annotation-config/>
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.cy"/>
我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig 是Spring的一个子项目,在$pring 4之后,它成为了一个核心功能!
配置环境,新建项目 spring-07
package com.cy.pojo;
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 + '\'' +
'}';
}
}
//这个也会spring容器托管,注册到容器中,因为他本来就是一个@Component
//@configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@ComponentScan("com.cy.pojo")
@Import(QingConfig2.class)
public class QingConfig {
//注册一个bean ,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();
}
}
//这个也会spring容器托管,注册到容器中,因为他本来就是一个@Component
//@configuration代表这是一个配置类,就和我们之前看的beans.xml
@Configuration
@ComponentScan("com.cy.pojo")
public class QingConfig2 {
//注册一个bean ,就相当于我们之前写的一个bean标签
//这个方法的名字,就相当于bean标签中的id属性
//这个方法的返回值,就相当于bean标签中的class属性
@Bean
public User getUser(){
return new User();
}
}
测试:
package com.cy.test;
import com.cy.config.QingConfig;
import com.cy.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(QingConfig.class);
User getUser = context.getBean("getUser",User.class);
System.out.println(getUser.getName());
}
}
为什么要学代理模式?
因为这就是SpringAOP的底层! 【SpringAOP 和 SpringMVC】
代理模式分类:
//房子
public interface Rent {
public void rent();
}
//房东
public class landlord implements Rent {
public void rent(){
System.out.println("房东要出租房子");
}
}
//中介
public class Proxy implements Rent {
private landlord host;//房东
public void Proxy(){}
public Proxy(landlord host) {
this.host = host;
}
//中介附属功能
public void rent(){
host.rent();//代理租房
seeHouse();//中介带你去看房
hetong();//看完签合同
fare();//收费用
}
//看房
public void seeHouse(){
System.out.println("中介带你看房");
}
public void hetong(){
System.out.println("签租聘合同");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
//租客
public class Client {
public static void main(String[] args) {
//房东要租房子
landlord host = new landlord();
//代理,中介帮房东租房子,但是:代理一班会有附属的操作!
Proxy proxy=new Proxy(host);
//租客不用面对房东,直接找中介租房即可!
proxy.rent();
}
}
好处:
缺点:
代理就是增强方法的类,你每次要增强功能就只能新建一个代理类重新写
我们创建一个增删改查的功能,然后在此功能实现增加日志的功能(注意不能修改源代码 公司大忌)
public interface UserService {
//增删改查
public void add();
public void delete();
public void update();
public void query();
}
//真实对象
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 query() {
System.out.println("查询了一个用户");
}
}
package com.cy.demo02;
//代理对象
public class UserServierProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
log("add");
userService.add();
}
@Override
public void delete() {
log("delete");
userService.delete();
}
@Override
public void update() {
log("update");
userService.update();
}
@Override
public void query() {
log("query");
userService.query();
}
//日志方法
public void log(String msg){
System.out.println("[日志] 使用了"+msg+"方法");
}
}
//日志功能
public class Client {
public static void main(String[] args) {
UserServiceImpl userService =new UserServiceImpl();
UserServierProxy proxy = new UserServierProxy();
proxy.setUserService(userService);
proxy.query();
proxy.add();
proxy.delete();
proxy.update();
}
}
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:
基于接口的动态代理
基于接口:JDK动态代理
基于类的动态代理
基于类: cglib
java字节码实现: javasist
需要了解两个类:
java.lang.reflect.Proxy
Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。(大白话:这是一个静态类,类里边有方法得到代理类)
//为某个接口创建代理Foo :
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
newInstance(handler);
//或更简单地:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
public static 类<?> getProxyClass(ClassLoader loader,
类<?>... interfaces)
throws IllegalArgumentException
/*给定类加载器和接口数组的代理类的java.lang.Class对象。 代理类将由指定的类加载器定义,并将实现所有提供的接口。 如果任何给定的接口是非公开的,则代理类将是非公开的。 如果类加载器已经定义了接口相同置换的代理类,那么将返回现有的代理类; 否则,这些接口的代理类将被动态生成并由类加载器定义。
对可能传递给Proxy.getProxyClass的参数有几个Proxy.getProxyClass :
interfaces数组中的所有类对象都必须表示接口,而不是类或原始类型。
interfaces数组中没有两个元素可能是指相同的类对象。
所有的接口类型必须通过指定的类加载器的名称可见。 换句话说,对于类加载器cl和每个接口i ,以下表达式必须为真:
Class.forName(i.getName(), false, cl) == i 所有非公共接口必须在同一个包中; 否则代理类将不可能实现所有接口,而不管其中定义了什么包。
对于具有相同签名的指定接口的任何成员方法集合:
如果任何方法的返回类型是原始类型或void,则所有方法必须具有相同的返回类型。
否则,其中一个方法必须具有一个返回类型,该类型可以分配给其余方法的所有返回类型。
生成的代理类不能超过虚拟机对类施加的任何限制。 例如,VM可以将类可以实现的接口数量限制为65535; 在这种情况下, interfaces阵列的大小不得超过65535。
如果任何这些限制被违反, Proxy.getProxyClass将抛出一个IllegalArgumentException 。 如果interfaces数组参数或其任何元素为null ,则将抛出一个NullPointerException 。
请注意,指定的代理接口的顺序是重要的:具有相同组合的接口但不同顺序的代理类的两个请求将导致两个不同的代理类。
参数
loader - 类加载器来定义代理类
interfaces - 要实现的代理类的接口列表
结果
在指定的类加载器中定义并实现指定接口的代理类 */
public static Object newProxyInstance(ClassLoader loader,
类<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
/*返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
Proxy.newProxyInstance因为与IllegalArgumentException相同的原因而Proxy.getProxyClass 。
参数
loader - 类加载器来定义代理类
interfaces - 代理类实现的接口列表
h - 调度方法调用的调用处理函数
结果
具有由指定的类加载器定义并实现指定接口的代理类的指定调用处理程序的代理实例 */
Object invoke(Object proxy,
方法 method,
Object[] args)
throws Throwable处理代理实例上的方法调用并返回结果。 当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。
/*参数
proxy - 调用该方法的代理实例
method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
结果
从代理实例上的方法调用返回的值。 如果接口方法的声明返回类型是原始类型,则此方法返回的值必须是对应的基本包装类的实例; 否则,它必须是可声明返回类型的类型。 如果此方法返回的值是null和接口方法的返回类型是基本类型,那么NullPointerException将由代理实例的方法调用抛出。 如上所述,如果此方法返回的值,否则不会与接口方法的声明的返回类型兼容,一个ClassCastException将代理实例的方法调用将抛出。
异常
Throwable - 从代理实例上的方法调用抛出的异常。 异常类型必须可以分配给接口方法的throws子句中声明的任何异常类型java.lang.RuntimeException检查的异常类型java.lang.RuntimeException或java.lang.Error 。 如果检查的异常是由这种方法是不分配给任何的中声明的异常类型throws接口方法的子句,则一个UndeclaredThrowableException包含有由该方法抛出的异常将通过在方法调用抛出代理实例。 */
//房子
public interface Rent {
public void rent();
}
//房东
public class landlord implements Rent {
public void rent(){
System.out.println("房东要出租房子");
}
}
用这个类,自动生成代理类
package com.cy.demo03;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//等我们会用这个类,自动生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent){
this.rent=rent;
}
/*Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class>[] { Foo.class },
handler);*/
//这个代码是死的
public Object getProxy(){
return Proxy.newProxyInstance( //生成对象 new一个
this.getClass().getClassLoader(),//加载到类的哪一个位置
rent.getClass().getInterfaces(),//代表他代理的接口是哪个接口
this);//代表自己这个InvocationHandler
}
//真正执行的靠这个方法
//生成代理类(处理代理实例,并返回结果)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
Object result = method.invoke(rent, args);//invoke实现接口时重写的方法(代理类实例对象调用方法时会调用invoke()方法)
seelandlord();
fare();
return result;
}
public void seelandlord(){
System.out.println("中介带看房子");
}
public void fare(){
System.out.println("收中介费");
}
}
生成代理类
package com.cy.demo03;
public class Client {
public static void main(String[] args) {
//真实角色
landlord host=new landlord();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口
pih.setRent(host);//这句的意思是:我生成的代理类,我要去实现这个接口
Rent proxy = (Rent) pih.getProxy();//这里的proxy就是动态生成的,我们并没有写
//输出结果
proxy.rent();
}
}
通过此方法,我们优化之前的增删改查
package com.cy.demo04;
import com.cy.demo03.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//等我们会用这个类,自动生成代理类
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);
}
//生成代理类(处理代理实例,并返回结果)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
package com.cy.demo04;
import com.cy.demo02.UserService;
import com.cy.demo02.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService=new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//设置要代理的对象
pih.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}
小结:
动态代理的好处:
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生泛型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
提供生命事务:允许用户自定义切面
SpringAop中,通过Advice定义横切逻辑,Spring中支持的5种类型的Advice
【重点】使用AOP织入,需要依赖包
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
eg:在执行UserService实现类的所有方法时,增加日志功能
UserServer接口
public interface UserService {
public void add();
public void update();
public void delete();
public void select();
}
UserServer实现类
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void select() {
System.out.println("查询了一个用户");
}
}
Log类
package com.cy.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//Method:要执行的目标对象方法
//object:参数(args: arguments to the method)
//target:目标对象 (target:target of the method invocation)
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
AfterLog
package com.cy.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
//returnValue:返回值
//Method:要执行的目标对象方法
//object:参数(args: arguments to the method)
//target:目标对象 (target:target of the method invocation)
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "方法,返回值为" + returnValue);
}
}
applicationContext.xml 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.cy.service.UserServiceImpl"/>
<bean id="log" class="com.cy.log.Log"/>
<bean id="afterLog" class="com.cy.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.cy.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
aop:config>
beans>
测试:
package com.cy.test;
import com.cy.service.UserService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理必须代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
}
diy
package com.cy.diy;
public class DiyPoinCut {
public void beforeMethod() {
System.out.println("======方法执行之前======");
}
public void afterMethod () {
System.out.println("======方法执行之后======");
}
}
applicationContext.xml 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.cy.service.UserServiceImpl"/>
<bean id="log" class="com.cy.log.Log"/>
<bean id="afterLog" class="com.cy.log.AfterLog"/>
<bean id="diy" class="com.cy.diy.DiyPoinCut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="point" expression="execution(* com.cy.service.UserServiceImpl.*(..))"/>
<aop:before method="beforeMethod" pointcut-ref="point"/>
<aop:after method="afterMethod" pointcut-ref="point"/>
aop:aspect>
aop:config>
beans>
package com.cy.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//方式三:使用注解方式实现AOP
@Aspect //标注这个类是一个切面
public class Annotation {
//@Before("")中的内容就是写切入点
//切入点:execution:表达式,execution(*(修饰词) *(返回值) *(类名) *(方法名) *(参数)) ..任意参数
@Before("execution(* com.cy.service.UserServiceImpl.*(..))")
public void before () {
System.out.println("====方法执行前====");
}
@After("execution(* com.cy.service.UserServiceImpl.*(..))")
public void after () {
System.out.println("====方法执行后====");
}
//在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
@Around("execution(* com.cy.service.UserServiceImpl.*(..))")
public void around (ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前");
Signature signature = pjp.getSignature();//获得签名
System.out.println("signature" + signature);
Object proceed = pjp.proceed();//执行方法
System.out.println("环绕后");
}
}
applicationContext.xml 配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.cy.service.UserServiceImpl"/>
<bean id="log" class="com.cy.log.Log"/>
<bean id="afterLog" class="com.cy.log.AfterLog"/>
<bean id="Annotation" class="com.cy.diy.Annotation"/>
<aop:aspectj-autoproxy/>
beans>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
<scope>testscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.22version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.3version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
dependencies>
IDAE连接数据库:如果忘记 看此教程(IDEA连接数据库)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=false&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" />
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/cy/mapper/*.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
beans>
<configuration>
<typeAliases>
<package name="com.cy.pojo"/>
typeAliases>
configuration>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<import resource="spring-dao.xml"/>
<bean id="userMapper" class="com.cy.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
beans>
package com.cy.pojo;
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String pwd;
}
package com.cy.mapper;
import com.cy.pojo.User;
import java.util.List;
public interface UserMapper {
public List<User> selectUser();
}
package com.cy.mapper;
import com.cy.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
//在原来,我们的所有操作,都使用sqLSession来执行,现在都使用sqLSessionTemplate;
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession){
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
package com.cy.test;
import com.cy.mapper.UserMapper;
import com.cy.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
public class MyTest {
@Test
public void test() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法,就像下面这样:
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> selectUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUser();
//return getSqlSession().getMapper(UserMapper.class).selectUser();
return users;
}
}
实际上是整合mybatis一与整合mybatis二是一样的方法,只不过二继承了SqlSessionDaoSupport ,在getSqlSession(),做的也是setSqlSessionTemplate
事务的ACID原则: