1.spring 1.1简介:
2002,首次推出了spring框架的雏形:interface 21 框架
spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版
Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,他不是计算机专业而是音乐学
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
SSH: Structs+Spring+Hibernate!
SSM:SpringMVC+Spring+Mybatis!
官网:https://spring.io/projects/spring-framework
官方下载文档:http://repo.spring.io/release/org/springframework/spring (有点bug)
GitHub:https://github.com/spring-projects/spring-framework
<dependency > <groupId > org.springframework</groupId > <artifactId > spring-webmvc</artifactId > <version > 5.2.0.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.2.0.RELEASE</version > </dependency >
1.2优点
spring是一个开源的免费的框架(容器)
spring是一个轻量级的、非入侵式的框架
控制反转(IOC)面向切面编程(AOP)
支持事务的处理,对框架整合的支持
总结一句话:spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3组成
1.4扩展 在spring的官方介绍:现代Java开发,说白就是基于spring的开发
Spring Boot
一个快速开发的脚手架
基于spring boot可以快速的开发单个微服务
约定大于配置
Spring Cloud
Spring Cloud是基于spring boot实现的
因为现在大多数公司都在使用spring boot进行快速开发,学习spring boot的前提,需要完全掌握spring及springmvc 承上启下的 作用
弊端:发展了太久之后,违背了原来的理念,配置十分繁琐。
2.IOC理论推论
public interface UserDao { void getUser () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class UserDaoImpl implements UserDao { public void getUser () { System.out.println("默认获取用户的数据" ); } }public class UserDaoMysqlImpl implements UserDao { public void getUser () { System.out.println("mysql获取用户数据" ); } }public class UserDaoOracleImpl implements UserDao { public void getUser () { System.out.println("oracle获取用户数据" ); } }public class UserDaoSqlServerImpl implements UserDao { public void getUser () { System.out.println("SqlServer获取用户数据" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public interface UserService { void getUser () ; }public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao (UserDao userDao) { this .userDao = userDao; } public void getUser () { userDao.getUser(); } }
public class MyTest { public static void main (String[] args) { UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(new UserDaoMysqlImpl()); userService.getUser(); } }
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码,如果程序代码量十分大,修改一次的成本代价十分昂贵!
我们使用一个set接口实现
private UserDao userDao;public void setUserDao (UserDao userDao) { this .userDao = userDao; }
之前,程序是主动创建对象,控制权在程序员手上
使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象
这种思想,从本质上决解了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大减低,可以更加专注的在业务的是实现上!这是IOC的原型
2.1IOC本质 控制反转IOC,是一种设计思想,DI(依赖注入)是实现IOC的一种方法, 也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建有程序自己控制,控制反转后将对象的创建转移给第三方 ,个人认为所谓控制反转就是:获得依赖对象的方式反转了
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的
控制反转是一种描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在spring中实现控制反转的是IOC容器,其实现方法是依赖注入
3.HelloSpring(spring-02-hellospring)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="hello" class ="com.sise.pojo.Hello" > <property name ="str" value ="Spring" /> </bean > </beans >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.sise.pojo;public class Hello { private String str; public String getStr () { return str; } public void setStr (String str) { this .str = str; } @Override public String toString () { return "Hello{" + "str='" + str + '\'' + '}' ; } }
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Hello hello = (Hello) context.getBean("hello" ); System.out.println(hello.toString()); } }
3.1思考问题?
hello对象是由spring创建的
hello对象的属性是由spring容器设置的
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用spring后,对象是由spring来创建的
反转:程序本身不创建对象,而变成被动的接收对象
依赖注入:就是利用set方法来进行 注入的
IOC是一种编程思想,有主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码
🆗,到了现在,我们彻底不用在程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的ioc一句话搞定:对象由spring来创建、管理、装备
4.ioc创建对象的方式(四种)(spring-02-ioc2)
实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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); } }
配置文件
<bean id ="user" class ="com.sise.pojo.User" > <property name ="name" value ="张三" /> </bean >
测试
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) { this .name = name; }
配置文件
<bean id ="user" class ="com.sise.pojo.User" > <constructor-arg index ="0" value ="狂神说Java" /> </bean > <bean id ="user" class ="com.sise.pojo.User" > <constructor-arg type ="java.lang.String" value ="雄安" /> </bean > <bean id ="user" class ="com.sise.pojo.User" > <constructor-arg name ="name" value ="小红" /> </bean >
测试
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); User user = (User) context.getBean("user" ); user.show(); } }
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
5.spring的配置 5.1别名 <alias name ="user" alias ="userNew" />
5.2bean的配置 <bean id ="userT" class ="com.sise.pojo.UserT" name ="userT2, u2,u3" > <constructor-arg name ="name" value ="雄安名" /> </bean >
5.3improt 这个improt,一般用于团队开发使用,它可以将多个配置文件,导入合并为一个
假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以用improt将所有人的beans.xml合并为一个总的
张三
李四
王五
applicationContext.xml
<import resource ="beans.xml" /> <import resource ="beans2.xml" /> <import resource ="beans3.xml" />
使用的时候,直接使用总的配置就可以了
6.依赖注入(spring-04-di) 6.1构造器注入 前面已经说过
6.2set方式注入【重点】 依赖注入:set注入
依赖:bean对象的创建依赖于容器
注入:bean对象中的所有属性,由容器来注入
【环境搭建】
public class Address { private String address; public String getAddress () { return address; } public void setAddress (String address) { this .address = address; } }
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;
<?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 ="student" class ="com.sise.pojo.Student" > <property name ="name" value ="张三" /> </bean > </beans >
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); Student student = (Student) context.getBean("student" ); System.out.println(student.getName()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <?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 ="address" class ="com.sise.pojo.Address" > <property name ="address" value ="广州" /> </bean > <bean id ="student" class ="com.sise.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 ="121321213121" /> <entry key ="银行卡" value ="11453413151431" /> </map > </property > <property name ="games" > <set > <value > LOL</value > <value > COC</value > <value > BOB</value > </set > </property > <property name ="wife" > <null /> </property > <property name ="info" > <props > <prop key ="driver" > 112313</prop > <prop key ="url" > 男</prop > <prop key ="username" > root</prop > <prop key ="password" > 4564123</prop > </props > </property > </bean > </beans >
6.3扩展方式注入 我们可以使用p命名空间和 c命名空间进行注入
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="user" class ="com.sise.pojo.User" p:name ="张三" p:age ="18" /> <bean id ="user2" class ="com.sise.pojo.User" c:name ="李四" p:age ="20" /> </beans >
public void test2 () { ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml" ); User user = context.getBean("user" , User.class); System.out.println(user); }
注意点
6.4bean的作用域
Scope
Description
singleton
(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype
Scopes a single bean definition to any number of object instances.
request
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
session
Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
application
Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocket
Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.
<bean id ="user2" class ="com.sise.pojo.User" c:name ="李四" p:age ="20" scope ="singleton" />
原型模式:每次从容器中get的时候,都会产生一个新对象
<bean id ="user2" class ="com.sise.pojo.User" c:name ="李四" c:age ="20" scope ="prototype" />
其余的request、application、session这些只能在web开发中使用到
7.bean的自动装配(spring-05-autowired)
自动装备是spring满足bean依赖一种方式
spring会在上下文中自动寻找,并只给bean装配属性
在spring中由三种装配的方式
在xml中显示的配置
在Java中显示配置
隐式的自动装配bean
7.1测试 环境搭建:一个人有两个宠物
<?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 ="cat" class ="com.sise.pojo.Cat" /> <bean id ="dog" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" > <property name ="name" value ="张三" /> <property name ="dog" ref ="dog" /> <property name ="cat" ref ="cat" /> </bean > </beans >
public class MyTest { @Test public void test1 () { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml" ); People people = context.getBean("people" , People.class); people.getDog().shout(); people.getCat().shout(); } }
7.2byname自动装备 <bean id ="cat" class ="com.sise.pojo.Cat" /> <bean id ="dog" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" autowire ="byName" > <property name ="name" value ="张三" />
7.3bytype自动装配 <bean id ="cat" class ="com.sise.pojo.Cat" /> <bean id ="dog1111" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" autowire ="byType" > <property name ="name" value ="张三" /> </bean >
总结
byname的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
bytype的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致
7.4使用注解实现自动装配 jdk1.5支持的注解,spring2.5就支持注解了
The introduction of annotation-based configuration raised the question of whether this approach is “better” than 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/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 >
@Autowired
直接在属性中使用即可,也可以在set方式上使用
使用autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(spring)容器中存在,且符合名字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 /> <bean id ="cat" class ="com.sise.pojo.Cat" /> <bean id ="dog" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" /> </beans >
pojo类
@Autowired private Cat cat; @Autowired private Dog dog; private String name;
@Qualifier
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value=”xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入
核心配置文件
<bean id ="cat11" class ="com.sise.pojo.Cat" /> <bean id ="cat111" class ="com.sise.pojo.Cat" /> <bean id ="dog22" class ="com.sise.pojo.Dog" /> <bean id ="dog222" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" />
pojo类
@Autowired @Qualifier(value = "cat111") private Cat cat;@Autowired @Qualifier(value = "dog22") private Dog dog;private String name;
@Resource
pojo类
@Resource private Cat cat; @Resource private Dog dog; private String name;
核心配置文件
<bean id ="cat11" class ="com.sise.pojo.Cat" /> <bean id ="dog22" class ="com.sise.pojo.Dog" /> <bean id ="people" class ="com.sise.pojo.People" />
总结
@Resource和@Autowired的区别:
都是用来自动装配的,都可以放在属性字段上
@Autowired 通过byType的方式实现,而且必须要求这个对象存在【常用】
@Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就报错【常用】
执行顺序不同:@Autowired是通过byType的方式实现。@Resource默认通过byname的方式实现
8.使用注解开发(spring-06-anno) 在spring4之后,要使用注解开发,必须保证aop的包导入了
使用注解需要导入context约束,增加注解的支持
<?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 /> </beans >
8.1bean 核心配置文件
<context:component-scan base-package ="com.sise.pojo" /> <context:annotation-config />
pojo类
@Component public class User { public String name = "张三" ; }
测试类
public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); User user = (User) context.getBean("user" ); System.out.println(user.name); }
@Component:组件,放在类上,说明这个类被spring管理了,就是bean!
8.2属性如何注入 @Component public class User { @Value("李四") public String name; }
8.3衍生的注解 @Component有几个衍生注解,我们在web开发中,会按照mvc三层购加分层
dao【@Repository】
service【@Service】
controller【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到spring中,装配bean
8.4自动装配置 @Autowired: 自动装配通过类型,名字 如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier (value="xxx" )@Nullable : 字段标识了这个注解,说明这个字段可以为null@Resource :自动装配通过名字,类型
8.5作用域 @Component @Scope("prototype") public class User { @Value("李四") public String name; }
8.6小结 xml和注解:
xml更加万能,适用于任何场合,维护简单方便
注解 不是自己类是用不了,维护相对复杂
xml和注解的最佳实践:
xml用来管理bean
注解只负责完成属性的注入
我们在使用过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
<context:component-scan base-package ="com.sise" /> <context:annotation-config />
9.使用Java的方式配置spring()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @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 + '\'' + '}' ; } }
@Configuration @ComponentScan("com.sise.pojo") @Import(KuangConfig2.class) public class KuangConfig { @Bean public User user () { return new User(); } }
public class MyTest { public static void main (String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(KuangConfig.class); User getUser = (User) context.getBean("user" ); System.out.println(getUser.getName()); } }
这种纯Java配置方式,在springboot中随处可见
10.代理模式(spirng-08-proxy) 为什么要 学习代理模式?
因为这就是springAOP的低层【springAOP 和 springMVC】
代理模式的分类:
10.1静态代理 角色分析:
抽象角色:一般会使用接口或者抽象类来解决
真实角色:被代理的角色
代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作
客户:访问代理对象的人
代码步骤
public interface Rent { public void rent () ; }
public class Host implements Rent { @Override public void rent () { System.out.println("房东要出租房子" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Proxy implements Rent { private Host host; public Proxy () { } public Proxy (Host host) { this .host = host; } @Override public void rent () { host.rent(); seeHost(); fare(); contract(); } public void seeHost () { System.out.println("中介带你看房" ); } public void fare () { System.out.println("收中介费" ); } public void contract () { System.out.println("签租借合同" ); } }
public class Client { public static void main (String[] args) { Host host = new Host(); Proxy proxy = new Proxy(host); proxy.rent(); } }
代理模式的好处
可以是真实角色的操作更加纯粹!不用去关注一些公共的业务
公共交给代理角色,实现了业务的分工
公共业务发生扩展的时候,方便集中管理
缺点
一个真实角色就会产生一个代理角色;代码量会翻倍;开发效率会变低
10.2加深理解
public interface UserService { public void add () ; public void delete () ; public void update () ; public void query () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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("查询了一个用户" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class UserServiceProxy 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(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService); proxy.query(); } }
10.3动态代理
动态代理的好处
可以是真实角色的操作更加纯粹!不用去关注一些公共的业务
公共交给代理角色,实现了业务的分工
公共业务发生扩展的时候,方便集中管理
一个动态代理类代理的是一个接口,一般就是对应的一类的业务
一个动态代理类可以代理多个类,只要是实现了同一个接口即可
处理程序类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class ProxyInvocationHandler implements InvocationHandler { private Rent rent; public void setRent (Rent rent) { this .rent = rent; } public Object getProxy () { return Proxy.newProxyInstance(this .getClass().getClassLoader(),rent.getClass().getInterfaces(),this ); } public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); Object result = method.invoke(rent, args); fare(); return result; } public void seeHouse () { System.out.println("中介带你看房子" ); } public void fare () { System.out.println("收中介费" ); } }
接口
public interface Rent { public void rent () ; }
真实角色
public class Host implements Rent { public void rent () { System.out.println("房东要出租房子" ); } }
测试类
public class Client { public static void main (String[] args) { Host host = new Host(); ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setRent(host); Rent proxy = (Rent) pih.getProxy(); proxy.rent(); } }
动态代理总结:
创建一个生成代理类的类,实现invocationHandlet接口
被代理的接口—-定义有参无参
创建一个生成代理类的方法,public Object xxxxx
返回值 类加载器,被代理对象的所有接口,invocationHandlet
实现接口自动生成public Object invoke(xxxxxx)
测试
创建一个被代理的对象即真实角色
创建一个与代理对象相关联的(即得到代理类)对象,并传入被代理对象进行代理
动态生成代理对象
代理对象相关联的对象调用生成代理类的方法
执行代理对象的方法都会被替换成执行invoke方法
11.AOP(spring-09-aop) 11.1什么是AOP AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是spring框架中的一个重要内容,是函数式编程的一种衍生范式。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
11.2AOP在spring中的作用 提供声明式事务:允许用户自定义切面
切面(aspect):横向关注点被模块化的特殊对象。即:它是一个类
通知(advice):切面必须要完成的工作。即:它是类中的一个方法
目标(target):被通知对象
代理(proxy):向目标对象应用通知之后创建的对象
切入点(pointcut):切面通知执行的“地点”的定义
连接点(jointpoint):于切入点匹配的执行点
在springAOP中,通过advice定义横切逻辑,spring中支持5中类型的advice:
即AOP在不改变原有的代码的情况下,去增加新的功能
11.3使用spring实现AOP 【重点】使用AOP需要导入一个依赖包
<dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.9.4</version > </dependency >
方式一:使用spring的API接口【主要springAPI接口实现】
public interface UserService { public void add () ; public void delete () ; public void update () ; public void select () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class UserServiceImpl implements UserService { public void add () { System.out.println("增加了一个用户" ); } public void delete () { System.out.println("删除了一个用户" ); } public void update () { System.out.println("更新了一个用户" ); } public void select () { System.out.println("查询了一个用户" ); } }
public class Log implements MethodBeforeAdvice { public void before (Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的" +method.getName()+"被执行了" ); } }
public class AfterLog implements AfterReturningAdvice { public void afterReturning (Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" +method.getName()+"方法,返回结果为:" +returnValue); } }
<bean id ="userService" class ="com.sise.service.UserServiceImpl" /> <bean id ="log" class ="com.sise.log.Log" /> <bean id ="afterLog" class ="com.sise.log.AfterLog" /> <aop:config > <aop:pointcut id ="pointcut" expression ="execution(* com.sise.service.UserServiceImpl.*(..))" /> <aop:advisor advice-ref ="log" pointcut-ref ="pointcut" /> <aop:advisor advice-ref ="afterLog" pointcut-ref ="pointcut" /> </aop:config >
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.add(); } }
方式二:使用自定义实现AOP【主要是切面定义】
public class DiyPointCut { public void before () { System.out.println("=========方法执行前==========" ); } public void after () { System.out.println("==========方法执行后=========" ); } }
<bean id ="userService" class ="com.sise.service.UserServiceImpl" /> <bean id ="diy" class ="com.sise.diy.DiyPointCut" /> <aop:config > <aop:aspect ref ="diy" > <aop:pointcut id ="point" expression ="execution(* com.sise.service.UserServiceImpl.*(..))" /> <aop:before method ="before" pointcut-ref ="point" /> <aop:after method ="after" pointcut-ref ="point" /> </aop:aspect > </aop:config >
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.add(); } }
方式三:使用注解实现AOP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Aspect public class AnnotationPointCut { @Before("execution(* com.sise.service.UserServiceImpl.*(..))") public void before () { System.out.println("=========方法执行前=========" ); } @After("execution(* com.sise.service.UserServiceImpl.*(..))") public void after () { System.out.println("=========方法执行后=========" ); } @Around("execution(* com.sise.service.UserServiceImpl.*(..))") public void around (ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前" ); Signature signature = jp.getSignature(); System.out.println("signature" +signature); Object proceed = jp.proceed(); System.out.println("环绕后" ); } }
<bean id ="annotationPointCut" class ="com.sise.diy.AnnotationPointCut" /> <aop:aspectj-autoproxy />
public class MyTest { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.add(); } }
12.整合mybatis 步骤:
导入相关jar包
junit
mybatis
mysql数据库
spring相关的
aop注入
mybatis-spring 【new】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 <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.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.1.9.RELEASE</version > </dependency > <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.8.13</version > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-spring</artifactId > <version > 2.0.2</version > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <version > 1.16.10</version > </dependency > </dependencies > <build > <resources > <resource > <directory > src/main/java</directory > <includes > <include > **/*.xml</include > </includes > <filtering > true</filtering > </resource > </resources > </build >
编写配置文件
测试
12.1回忆mybatis
编写实体类
编写核心配置文件
编写接口
编写mapper.xml
测试
12.2整合方式一
编写数据源配置
sqlSessionFactory
sqlSessionTemplate
需要给接口加实现类
将自己写的实现类,注入到spring中
测试使用即可
public interface UserMapper { public List<User> selectUser () ; }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.sise.dao.UserMapper" > <select id ="selectUser" resultType ="com.sise.pojo.User" > select * from mybatis.user; </select > </mapper >
public class UserMapperImpl implements UserMapper { private SqlSessionTemplate sqlSession; public void setSqlSession (SqlSessionTemplate sqlSession) { this .sqlSession = sqlSession; } public List<User> selectUser () { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.selectUser(); } }
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <typeAliases > <package name ="com.sise.pojo" /> </typeAliases > </configuration >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop ="http://www.springframework.org/schema/aop" xsi:schemaLocation ="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd" > <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& useUnicode=true& characterEncoding=UTF-8" /> <property name ="username" value ="root" /> <property name ="password" value ="123456" /> </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/sise/mapper/*.xml" /> </bean > <bean id ="sqlSession" class ="org.mybatis.spring.SqlSessionTemplate" > <constructor-arg index ="0" ref ="sqlSessionFactory" /> </bean > <bean id ="userMapper" class ="com.sise.mapper.UserMapperImpl" > <property name ="sqlSession" ref ="sqlSession" /> </bean > </beans >
public class MyTest { @Test public void test () throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml" ); UserMapper userMapper = context.getBean("userMapper" , UserMapper.class); List<User> userList = userMapper.selectUser(); for (User user : userList) { System.out.println(user); } } }
12.3整合方式二
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper { public List<User> selectUser () { return getSqlSession().getMapper(UserMapper.class).selectUser(); } }
<bean id ="userMapper2" class ="com.sise.mapper.UserMapperImpl2" > <property name ="sqlSessionFactory" ref ="sqlSessionFactory" /> </bean >
public class MyTest { @Test public void test () throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ); UserMapper userMapper = context.getBean("userMapper2" , UserMapper.class); List<User> userList = userMapper.selectUser(); for (User user : userList) { System.out.println(user); } } }
整合方式一:重点写sqlsession类,对spring注入
整合方式二:简化,不用手写sqlsession,只需要继承SqlSessionDaoSupport
13.声明式事务 13.1回顾事务
把一组业务当成一个业务来做:要么成功,要么失败
事务在项目开发中十分重要,涉及到数据的一致性问题,不能掉以轻心
确保完整性和一致性
事务的ACID
13.2spring中事务管理
声明式事务:AOP
编程式事务:需要在代码中,进行事务管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <bean id = "transactionManager" class = "org.springframework.jdbc.datasource.DataSourceTransactionManager" > <property name ="dataSource" ref ="dataSource" /> </bean > <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.sise.mapper.*.*(..))" /> <aop:advisor advice-ref ="txAdvice" pointcut-ref ="txPointCut" /> </aop:config >
思考:为什么需要事务?
如果不配置事务,可能存在数据提交不一致的情况下
如果我们不在spring中去配置声明式事务,我们就需要在代码中手动配置事务
事务在项目中开发十分重要,涉及到数据的一致性和完整性
14.Spring数据库开发(补充) 方式一:使用XML方式
创建一个数据库users
导入maven相关依赖依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <dependencies > <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.2.0.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.1.9.RELEASE</version > </dependency > </dependencies >
实体类Student
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public class Student { private int id; private String name; private String sno; public Student () { } public Student (int id, String name, String sno) { this .id = id; this .name = name; this .sno = sno; } 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; } public String getSno () { return sno; } public void setSno (String sno) { this .sno = sno; } @Override public String toString () { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", sno='" + sno + '\'' + '}' ; } }
接口StudentDao
public interface StudentDao { public int addStudent (Student student) ; public int deleteStudent (int id) ; public int updateStudent (Student student) ; public Student queryStudent (int id) ; public List<Student> queryAllStudent () ; }
接口实现类StudentDaoImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class StudentDaoImpl implements StudentDao { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate (JdbcTemplate jdbcTemplate) { this .jdbcTemplate = jdbcTemplate; } public int addStudent (Student student) { String sql = "insert into users(id,name,sno) values(?,?,?)" ; Object[] objects = new Object[]{ student.getId(), student.getName(), student.getSno() }; int add = this .jdbcTemplate.update(sql, objects); return add; } public int deleteStudent (int id) { String sql = "delete from users where id=?" ; int delete = this .jdbcTemplate.update(sql, id); return delete; } public int updateStudent (Student student) { String sql = "update users set name=?,sno=? where id=?" ; Object[] objects = new Object[]{ student.getName(), student.getSno(), student.getId() }; int update = this .jdbcTemplate.update(sql, objects); return update; } public Student queryStudent (int id) { String sql = "select * from users where id = ?" ; BeanPropertyRowMapper<Student> row = BeanPropertyRowMapper.newInstance(Student.class); Student student = this .jdbcTemplate.queryForObject(sql, row, id); return student; } public List<Student> queryAllStudent () { String sql = "select * from users" ; BeanPropertyRowMapper<Student> mapper = BeanPropertyRowMapper.newInstance(Student.class); List<Student> query = this .jdbcTemplate.query(sql, mapper); return query; } }
配置xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <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" 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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd" > <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/jdbc?useUnicode=true& characterEncoding=utf-8& useSSL=true" /> <property name ="username" value ="root" /> <property name ="password" value ="123456" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="studentDao" class ="com.sise.jdbc.StudentDaoImpl" > <property name ="jdbcTemplate" ref ="jdbcTemplate" /> </bean > </beans >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public class Test6 { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml" ); JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate" ); StudentDao studentDao = (StudentDao) context.getBean("studentDao" ); @Test public void createTableTest () { String sql="CREATE TABLE If Not Exists `users` (" + " `id` int(10) NOT NULL auto_increment, " + "`name` varchar(15) NOT NULL, " + " `sno` varchar(50) NOT NULL," + " PRIMARY KEY (`id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8;" ; jdbcTemplate.execute(sql); } @Test public void addStudent () { Student student = new Student(); student.setName("张三" ); student.setSno("11111" ); int i = studentDao.addStudent(student); if (i == 1 ){ System.out.println("增加学生成功" ); }else { System.out.println("失败" ); } } @Test public void deleteStudent () { int i = studentDao.deleteStudent(1 ); if (i == 1 ){ System.out.println("删除成功" ); }else { System.out.println("删除失败" ); } } @Test public void updateStudent () { Student student = new Student(); student.setId(2 ); student.setName("李四" ); student.setSno("000000" ); int i = this .studentDao.updateStudent(student); if (i == 1 ){ System.out.println("更新成功" ); }else { System.out.println("失败" ); } } @Test public void query () { Student student = this .studentDao.queryStudent(2 ); System.out.println(student); } @Test public void all () { List<Student> students = this .studentDao.queryAllStudent(); for (Student student : students) { System.out.println(student); } } }
提取数据库信息
建立properties文件
jdbc.driver =com.mysql.jdbc.Driver jdbc.url =jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8&useSSL=true jdbc.username =root jdbc.password =123456
xml引入该文件位置并修改数据库信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <context:property-placeholder location ="classpath:db.properties" /> //第二种方式://////////////////////////////////////// <bean class ="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" > <property name ="location" value ="db.properties" /> </bean > ///////////////////////////////////////////////<bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean > <bean id ="studentDao" class ="com.sise.jdbc.StudentDaoImpl" > <property name ="jdbcTemplate" ref ="jdbcTemplate" /> </bean >
方式二:通过包扫描机制
在xml增加包扫描机制
<context:component-scan base-package ="com.sise.jdbc" />
删掉实现类xml注入
<context:component-scan base-package ="com.sise.jdbc" /> <context:property-placeholder location ="classpath:db.properties" /> <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" > <property name ="driverClassName" value ="${jdbc.driver}" /> <property name ="url" value ="${jdbc.url}" /> <property name ="username" value ="${jdbc.username}" /> <property name ="password" value ="${jdbc.password}" /> </bean > <bean id ="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate" > <property name ="dataSource" ref ="dataSource" /> </bean >
在实现类上增加注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @Component("studentDao") public class StudentDaoImpl implements StudentDao { @Autowired private JdbcTemplate jdbcTemplate; public void setJdbcTemplate (JdbcTemplate jdbcTemplate) { this .jdbcTemplate = jdbcTemplate; } public int addStudent (Student student) { String sql = "insert into users(id,name,sno) values(?,?,?)" ; Object[] objects = new Object[]{ student.getId(), student.getName(), student.getSno() }; int add = this .jdbcTemplate.update(sql, objects); return add; } public int deleteStudent (int id) { String sql = "delete from users where id=?" ; int delete = this .jdbcTemplate.update(sql, id); return delete; } public int updateStudent (Student student) { String sql = "update users set name=?,sno=? where id=?" ; Object[] objects = new Object[]{ student.getName(), student.getSno(), student.getId() }; int update = this .jdbcTemplate.update(sql, objects); return update; } public Student queryStudent (int id) { String sql = "select * from users where id = ?" ; BeanPropertyRowMapper<Student> row = BeanPropertyRowMapper.newInstance(Student.class); Student student = this .jdbcTemplate.queryForObject(sql, row, id); return student; } public List<Student> queryAllStudent () { String sql = "select * from users" ; BeanPropertyRowMapper<Student> mapper = BeanPropertyRowMapper.newInstance(Student.class); List<Student> query = this .jdbcTemplate.query(sql, mapper); return query; } }
测试