Spring
1.1 Spring理念:使得现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架。
SSH: Struct2 +Spring+hibernate
SSM: SpringMvc+ Spring+Mybatis (Struct2 和SpringMvc很相似)
官方下载地址: https://repo.spring.io/ui/native/release/org/springframework/spring
Github: http://repo.spring.io/release/org/springframework/spring 在这个地址可以下载到所有的版本信息,而且是更新的。
Spring maven 包:
org.springframework
spring-webmvc
5.3.9
(Spring需要和Mybatis整合,就需要这个包)
org.springframework
spring-jdbc
5.3.9
1.2 Spring的优点:
1.Spring是一个开源的免费的框架(容器)!
2.Spring是一个轻量级,非入侵式的框架!
3.控制反转(IOC),面向切面编程(AOP)
4.支持事务的处理,对框架整合的支持!(几乎所有的java框架它都能整合)
==总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!==
1.3 Spring拓展:
Spring7大模块:
在Spring的官网中有这个介绍:现代化的Java开发!说白就是基于Spring的开发!
*Spring Boot
一个快速开发的脚手架
基于SpringBoot可以快速的开发单个服务器(比如一个mybatis项目)
约定大于配置!(和maven一样) ----契约即是约定 如果配置太多,就加大了人类的思维工作负担,不符合人类利用机器偷懒的初衷。干脆为所有配置提供一个默认选择,或者提供一个自助决策规则,如此建立起人与机器的基本约定。所以约定大于配置,其实是要建立起尽力减少配置项,采用约定方案的思想。在maven里面:在汇编时代 ,编程语言通过二进制对硬件直接编码,然后转成电气信息来处理信息,语言再往上抽离,就有诸如c语言这样面向过程的语言,进而再抽离有了目前面象对象的高级语言 java C++ 等,而在这些高级语言中,我们不再使用10进行对硬件的直接编码,而是约定出来一些叫 类啊,方法啊,属性啊,还有什么封装 多态 继承之类的专用的名称和技术,而这技术,是定制这套语言的设计师约定的啊,设计师约定编程框架,约定使用new来创建对象啊,等等… 而我们不用 fresh(新鲜的)来创建对象,因为创建对象已对用new来约定了
讲到这里,我感觉又有了更深一层的体会,即便是汇编语言,使用10进行编码,最后通过编号信息转为电气信息,这本质也是一种约定啊! 比如发送100000000.经过什么解析,然后在显示屏有对应的颜色~~ 此时,我感觉体内的知识体系大楼正在剧烈的晃动,关于约定大于配置其实不光是maven的体现,更应该是整个编程世界的体现,本质上约定大于配置就是实现物理世界和编程世界互通或互认的一种思维和技术实现.
而我们目前开发软件,一般都是基于IDE的,难道IDE不也是一种“约定大于配置”的体现吗?
而讲到maven,往往会特别重申它的“约定大于配置“的好处,是因为通过maven来构建一个项目,有它自己独道的好处,极大的便捷了我们的开发。
在IDE开发的基础上,maven又进一步的“约定大于配置“思维可以帮我们实现以下内容:
1 如果使用maven,它有仓库的概念,可以帮我们依赖jar包,方便我们管理jar包,在协同开发时,更优
2 maven有自己独特的本地目录结构,不受不同IDE开发的影响,用git或者SVN托管,有不错的结构
3 maven可作多模块开发,并可在父模块pom.xml中配置依赖和插件,方便多模块管理
Spring Boot 是构建所有基于Spring的应用程序的起点,Spring Boot旨在通过最少的Spring前期配置使您尽快启动并且运行。
*Spring cloud:
Spring cloud是基于Spring Boot实现的。
Spring 弊端:发展了太久以后,违背了原来的理念! 配置越来越多,变的十分繁琐,人称:“配置地狱(多到我们根本记不下来)”
IOC(控制反转理论推导(获得依赖对象的方式反转了)):
1.UserDao接口
package com.kuang.dao; public interface UserDao { void getUser(); }
2.UserDaoImpl 实现类
package com.kuang.dao; public class UserDaoImpl implements UserDao{ public void getUser() { System.out.println("默认获取用户数据"); } } //业务层制作一个事情就是去调用dao层
3.UserService 业务接口
package com.kuang.service; public interface UserService { void getUser(); }
4.UserServiceImpl 业务实现类
package com.kuang.service; import com.kuang.dao.UserDao; import com.kuang.dao.UserDaoImpl; import com.kuang.dao.UserDaoOracleImpl; public class UserServiceImpl implements UserService { /* //我们要用就直接拿过来(业务层要用dao层)调用 private UserDao userDao = new UserDaoOracleImpl(); 程序控制对象//在这里我们需要根据客户的需求去改原有的代码,这样是肯定不行的, 我们要去解决这个问题(设计模式,使用接口,创建set方法) 弊端:我们的程序适应不了用户的变更 */ private UserDao userDao; //使用set进行动态实现值得注入! public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void getUser() { userDao.getUser(); //我们业务层调的Dao层,它才能够实现 } }
Mytest:
import com.kuang.dao.UserDaoMysqlImpl; import com.kuang.dao.UserDaoOracleImpl; import com.kuang.service.UserServiceImpl; public class Mytest { public static void main(String[] args) { //用户实际调用的是业务层,dao层他们不需要接触 //三层架构,会去new一个业务层,不会直接到dao层 UserServiceImpl userService = new UserServiceImpl(); //userService.setUserDao(new UserDaoMysqlImpl()); 跟刚才有着革命性的变化 userService.setUserDao(new UserDaoOracleImpl()); userService.getUser(); } }
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,
修改一次的成本代价十分昂贵!
我们使用一个Set接口实现
private UserDao userDao;
//使用set进行动态实现值得注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
发生了革命性的变化!
*之前,程序是主动创建对象!控制权在程序员手上!(所以说用户的每一个需求都会让我们去改原来的代码)
*使用了set注入后,程序不在具有主动性,而是变成了被动的接受对象!
所以叫做控制反转,主要是思想,这种思想从本质上解决了问题,我们程序员不用再去管理对象的创建了(也就是不用去改变我们的代码了),由用户自己可以获取到了。
(就是你设计了一个系统,一个网页,其中存在很多的接口),系统的耦合性大大降低,在其中整合了IOC控制反转,可以更加专注的在业务的实现上。
IOC本质:
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现Ioc的一种方法,也有人认为DI只是Ioc的里那个一种方法。没有Ioc的程序中,我们使用面向对象编程,对象的创建和对象的依赖关系完全硬编码在程序中,对象的创建由程序(程序猿)自己控制,控制反转后将对象的创建转移给第三方。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
**控制反转是一种通过描述(XML或者注解) 并且通过第三方去生产或获取特定对象的方式,在spring中实现控制反转的是IoC容器,实现方法是依赖注入。
HelloSpring:
1.创建一个实体类pojo/Hello 提供一个str属性
package com.kuang.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 + '\'' + '}'; } }
2.配置beans.xml 容器
<?xml version="1.0" encoding="UTF-8"?>
3.写测试文件
import com.kuang.pojo.Hello; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Mytest { public static void main(String[] args) { //获取Spring的上下文对象! ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就好了 //你看我们现在没有去new Hello吧,但是Hello也出来了 Hello hello = (Hello) context.getBean("hello"); System.out.println(hello.toString()); } }
Ioc创建对象方式:
创建实体类:
package com.kuang.pojo; public class User { private String name; // public User(){ // System.out.println("User的无参构造"); //无参构造 // } //声明有参构造 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.xml
<?xml version="1.0" encoding="UTF-8"?>
创建测试类:Mytest
import com.kuang.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Mytest { public static void main(String[] args) { // new User(); //说白了spring帮我们在这里做了一个事情new一个User,等会我们要用Spring来做这个事情,接下来进行探讨 // Sprring容器:只要你bean了,它就给你实例化了,你要是想用直接get就好了 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user"); user.show(); } } //有参构造直接报错, Caused by: java.lang.NoSuchMethodException: com.kuang.pojo.User.() 不能被初始化 //总结:在配置文件加载的时候,容器中管理的对象就已经开始初始化了!
依赖注入
通过构造器注入:
属性除了可以直接初始化之外,我们也可以通过构造器来进行初始化
Hello.java
package com.bupt.pojo; import lombok.Data; @Data public class Hello { private String str; private int age; public Hello(String str, int age){ this.age = age; this.str = str; } public void show(){ System.out.println("show"); } }
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
MyTest.java文件
import com.bupt.pojo.Hello; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml"); Hello hello = classPathXmlApplicationContext.getBean("hello", Hello.class); hello.show(); } @Test public void test01(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Hello hello = context.getBean("hello", Hello.class); System.out.println(hello.getAge()); System.out.println(hello.getStr()); } @Test public void test02(){ ClassPathXmlApplicationContext contxt = new ClassPathXmlApplicationContext("beans.xml"); Hello hello1 = contxt.getBean("hello1", Hello.class); System.out.println(hello1.getAge()); System.out.println(hello1.getStr()); } @Test public void test03(){ ClassPathXmlApplicationContext contxt = new ClassPathXmlApplicationContext("beans.xml"); Hello hello2 = contxt.getBean("hello2", Hello.class); System.out.println(hello2.getAge()); System.out.println(hello2.getStr()); } }
Set注入:
环境搭建:
复杂类:Address
package com.kuang.pojo; public class Address { private Address address; public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
真实测试对象:
package com.kuang.pojo; import java.util.*; public class Student { private String name; private Address address; private String[] books; private List hobbys; private Map card; private Set games; private String wife; private Properties info; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public String[] getBooks() { return books; } public void setBooks(String[] books) { this.books = books; } public List getHobbys() { return hobbys; } public void setHobbys(List hobbys) { this.hobbys = hobbys; } public Map getCard() { return card; } public void setCard(Map card) { this.card = card; } public Set getGames() { return games; } public void setGames(Set games) { this.games = games; } public String getWife() { return wife; } public void setWife(String wife) { this.wife = wife; } public Properties getInfo() { return info; } public void setInfo(Properties info) { this.info = info; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", address=" + address + ", books=" + Arrays.toString(books) + ", hobbys=" + hobbys + ", card=" + card + ", games=" + games + ", wife='" + wife + '\'' + ", info=" + info + '}'; } }
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
测试类:
import com.kuang.pojo.Student; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Mytest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.getName()); } }
XML Shortcut with the p-namespace
bean> beans>
bean> bean> beans>
XML Shortcut with the c-namespace
bean> beans>
P命名和C命名的注入:
User
package com.kuang.pojo; import java.security.PrivateKey; public class User { private String name; private int age; public User() { } //底下这一个是有参构造器 public User public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge(String age) { return this.age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
Mytest测试:
import com.kuang.pojo.User; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Mytest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user"); //User user = context.getBean("user", User.class); //有了user.class 每次就不用再去强转了 System.out.println(user); } @Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user2"); System.out.println(user); } }
6.4 Bean 的作用域
在spring中,那些组成应用程序的主题及由Spring Ioc容器所管理的对象,被称为bean,简单来说bean就是由Ioc容器初始化,装配以及管理的对象。
Singleton
当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:
测试:
@Test public void test03(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user = (User) context.getBean("user"); User user2 = (User) context.getBean("user"); System.out.println(user==user2); }
每次获取到的都是user对象
Prototype
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:
或者
结果:为false,就是当我们去获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。所以在这里获取到的是user和user2
@Test public void test2(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user2"); User user2 = (User) context.getBean("user2"); System.out.println(user==user2); } }
7.Bean的自动装配
自动装配说明:
*自动装配是使用spring满足bean依赖的一种方法
*spring会在应用上下文中为某个bean寻找其依赖的bean
Spring中bean有三种装配机制,分别是:
1.在xml中显式配置;
2.在java中显式配置
3.隐式的bean发现机制和自动装配
测试环境搭建
1.新建一个项目
2.新建两个实体类,Cat,Dog 都有一个叫的方法
package com.kuang.pojo; public class Cat { public void shout(){ System.out.println("miao"); } }
package com.kuang.pojo; public class Dog { public void shout(){ System.out.println("wang"); } }
在创建一个people有这两个动物
package com.kuang.pojo; public class People { private Dog dog; private Cat cat; private String name; public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "People{" + "dog=" + dog + ", cat=" + cat + ", name='" + name + '\'' + '}'; } }
编写配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?>
在写测试文件
public class MyTest { @Test public void testMethodAutowire() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); User user = (User) context.getBean("user"); user.getCat().shout(); user.getDog().shout(); } }
byName 自动装配(按名称自动装配)
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">
byType自动装配:(按类型自动装配)
使用autowire byType 首先需要保证:同一类型的对象,在Spring容器中唯一,如果不唯一,就会报不唯一的异常
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">
小结:
*byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
*byType 的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
8.使用注解实现自动装配
@Autowired //也可以去掉set,也能够自动装配
//@Qualifier(value = "cat111") //如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候, // 我们可以 @Qualifier(value = "cat111") 使用去配置 @Autowired的使用,指定一个唯一的bean对象注入
@Resource(name = "dog222")//如果它找不到相同的cat,就会报错,当然也可以有办法结解决,看左边 @Resource(name = "cat222")
测试:
import com.kuang.pojo.Peopel; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Mytest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Peopel people = context.getBean("people", Peopel.class); people.getCat().shout(); people.getDog().shout(); } }
使用byname和bytype小结:
*byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
*byType 的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
使用注解实现自动装配小结:
@Resource 和@Autowired 的区别:
*都是用来自动装配的,都可以放在属性字段上
*@Autowired 通过byname的方式实现,而且必须要求这个对象存在不然就会空指针【常用】
*@Resource默认通过byname的方法实现,如果找不到名字就用bytype实现!如果都找不到就报错!
*执行顺序不同:@Autowired 通过bytype的方式实现。 @Resource 默认通过byname的方式实现。
@Autowired:自动装配通过类型。名字 如果Autowired 不能够唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”) @Resource :自动装配通过名字,类型。 @Nullable 字段标记了这个注解,说明这个字段可以为null。
package com.kuang.pojo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import javax.annotation.Resource; public class Peopel { // @Autowired //@Qualifier(value = "dog222") @Resource(name = "dog222")//如果它找不到相同的cat,就会报错,当然也可以有办法结解决,看左边 private Dog dog; // @Autowired //也可以去掉set,也能够自动装配 //@Qualifier(value = "cat111") //如果@Autowired 自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候, // 我们可以 @Qualifier(value = "cat111") 使用去配置 @Autowired的使用,指定一个唯一的bean对象注入 @Resource(name = "cat222") private Cat cat; private String name; public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Peopel{" + "dog=" + dog + ", cat=" + cat + ", name='" + name + '\'' + '}'; } }
9.使用注解开发
我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
1、配置扫描哪些包下的注解
2、在指定包下编写类,增加注解
@Component("user") // 相当于配置文件中 public class User { public String name = "秦疆"; }
3、测试
@Test public void test(){ ApplicationContext applicationContext =new ClassPathXmlApplicationContext("beans.xml"); User user = (User) applicationContext.getBean("user"); System.out.println(user.name); }
属性注入
使用注解注入属性
1、可以不用提供set方法,直接在直接名上添加@value("值")
@Component("user") // 相当于配置文件中 public class User { @Value("秦疆") // 相当于配置文件中 public String name; }
2、如果提供了set方法,在set方法上添加@value("值");
@Component("user") public class User { public String name; @Value("秦疆") public void setName(String name) { this.name = name; } }
衍生注解
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
作用:
10.1,静态代理
角色分析:
*抽象角色(比如共同完成的一个事情租房,结婚):一般会使用接口或者抽象类来解决
*真实角色:被代理的角色
*代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
*客户:访问代理对象的人!
代码步骤:
创建一个抽象角色:Rent 接口
package com.kuang.demo01; //抽象角色,共同完成的一个事情 public interface Rent { public void rent(); }
创建一个真实角色:Host(房东)
package com.kuang.demo01; //房东 房东要去租房,所以要继承Rent的接口 public class Host implements Rent{ @Override public void rent() { System.out.println("房东要出租房子!"); } }
创建一个代理角色
package com.kuang.demo01; public class Proxy implements Rent{ private Host host; //无参构造 public Proxy() { } //有参构造 public Proxy(Host host) { this.host = host; } @Override public void rent() { host.rent(); seeHouse(); } //看房 public void seeHouse(){ System.out.println("中介带你看房!"); } }
创建客户端访问代理(我:租房)
package com.kuang.demo01; //我要去租房子 public class Client { public static void main(String[] args) { Host host = new Host(); //host.rent(); //代理。中介帮房东租房子,但是呢?代理角色一般会有一些附属操作! Proxy proxy = new Proxy(host); //用简单的构造,就把房东这个角色给了代理 //你不用面对房东,直接找中介租房即可! proxy.rent(); } }
代理模式的好处:
*可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
*公共也就交给代理角色!实现了业务的分工!
*公共业务发生拓展的时候,方便集中管理!
缺点:
*一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低!
10.3 动态代理
*动态代理和静态代理角色一样
*动态代理的代理类是动态生成的,不是我们直接写好的!
*动态代理分为两大类:基于接口的动态代理,基于类的动态代理
‘ 基于接口---JDK动态代理(我们在这里使用)
’ 基于类:cglib
‘ java字节码实现 : javasist
需要了解两个类:Proxy; 代理 invocationHandler: 调用处理程序 (是由代理实现的,调用处理程序实现的接口,每个代理都有一个关联的调用处理程序,当在代理实例上调用方法时,方法调用将被编码并且分派到其调用处理程序的invoke方法)
创建一个接口:Rent
package com.kuang.demo03; public interface Rent { public void rent(); }
创建一个房东:
package com.kuang.demo03; public class Host implements Rent{ @Override public void rent() { System.out.println("房东要租房子"); } }
创建代理调用处理程序:
package com.kuang.demo03; //代理调用处理程序 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //我们会用这个类,自动生成代理类! public class ProxyInvocationHandler implements InvocationHandler { //Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader() // new Class<?>[] { Foo.class} // handler); //被代理的接口 private Rent rent; public void setRent(Rent rent) { this.rent = rent; } //生成得到代理类 这个代码是死的,只用更改rent 就好了 this.getClass().getClassLoader()类加载到哪个位置 ent.getClass().getInterfaces() 表示要代理的接口 this代表它自己InvocationHandler public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); } //处理代理实例,并且返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //动态代理的本质,就是使用反射机制 Object result = method.invoke(rent, args); return result; } }
创建实现类:Client
package com.kuang.demo03; public class Client { public static void main(String[] args) { //真实角色 Host host = new Host(); //代理角色 现在没有 ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); //通过调用程序处理角色来处理我们要调用的接口对象! proxyInvocationHandler.setRent(host); //我生成的代理类,我要去实现接口 //用返回代理的方法 getProxy Rent proxy = (Rent) proxyInvocationHandler.getProxy(); //这里的proxy就是动态生成的,我们并没有写 proxy.rent(); } }
我们可以创建ProxyInvocationHandler 当作工具类
package com.kuang.demo04; //代理调用处理程序 import com.kuang.demo02.UserServiceImpl; import com.kuang.demo03.Rent; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //我们会用这个类,自动生成代理类! public class ProxyInvocationHandler implements InvocationHandler { //Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader() // new Class<?>[] { Foo.class} // handler); //被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } //生成得到代理类 这个代码是死的,只用更改rent 就好了 this.getClass().getClassLoader()类加载到哪个位置 ent.getClass().getInterfaces() 表示要代理的接口 this代表它自己InvocationHandler 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+"方法"); } }
创建Client
package com.kuang.demo04; import com.kuang.demo02.UserService; import com.kuang.demo02.UserServiceImpl; import com.kuang.demo03.Rent; public class Client { public static void main(String[] args) { //真实角色 UserServiceImpl service = new UserServiceImpl(); //代理角色 不存在 ProxyInvocationHandler pih = new ProxyInvocationHandler(); //1.代理接口,设置要代理的对象 pih.setTarget(service); //2.动态生成代理类 UserService proxy = (UserService) pih.getProxy(); proxy.add(); } }
动态代理的优点:
*可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
*公共也就交给代理角色!实现了业务的分工!
*公共业务发生拓展的时候,方便集中管理!
缺点:
*一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低!
*一个动态代理类代理的是一个接口,一般就是对应的一类业务!
*一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
12.1,回忆Mybatis
1.编写实体类
2.编写核心配置文件
3.编写接口
4.编写Mapper.xml
5.测试
Spring整合Mybatis 方式一:
1.编写数据源
2.sqlSessionFactory
3.sqlSessionTempalte
4.需要给接口加上实现类,注入到spring中
5.测试即可
1.spring-dao.xml
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">
2.UserMapperImpl
package com.kuang.mapper;
import com.kuang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
//我们有xml是进行写sql的,但是我们真正执行的由于
//
//
//
// 变成了面向对象的,是不是得需要类啊
public class UserMapperImpl implements UserMapper {
//我们的所有操作,都使用sqlSession来执行,现在我们都使用 SqlSessionTemplate
private SqlSessionTemplate sqlSession; //我们叫它sqlSession就好了
//有了sqlSession 我们需要把它注入进来,等会我们在spring里面注册的时候直接给他丢进去就行了。
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
//你看我们刚才所有的东西都是在测试里面写的,现在我们整合mybatis-spring,交到类里面去做了,我们等会直接掉这个类的方法就完了
@Override
public List selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
3.测试类Mytest
import com.kuang.mapper.UserMapper;
import com.kuang.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
@Test
public void test() throws IOException {
// String resources="mybatis-config.xml";
// InputStream in = Resources.getResourceAsStream(resources);
//
// SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
// SqlSession sqlSession = sessionFactory.openSession(true);
//
// UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// List userList = mapper.selectUser();
//
// for (User user : userList) {
// System.out.println(user);
// }
//就不用这些东西了,以后mybatis就内部集成了
ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
UserMapper userMapper = (UserMapper) context.getBean("userMapper");
for (User user : userMapper.selectUser()) {
System.out.println(user);
}
}
}
事务ACID原则:
1.原子性
2.一致性
3.隔离性 多个业务可能操作同一个资源,防止数据损坏
4.持久性 事务一旦提交,无论系统发生什么问题,结果都不会在被影响,被持久化的写到存储器中!
13.声明式事务
1.声明式事务:AOP
2.编程式事务:需要在代码中,进行事务的管理
思考:为什么需要事务?
*如果不配置事务,可能存在数据提交不一致的情况下;
*如果我们不在SPRING中,我们就需要在代码中手动配置事务!
*事务在项目的开发中十分重要,设计到数据的一致性和完整性问题,不容马虎!
这个代码是固定的,谁需要配置事务就在这里使用AOP织入到那个地方去就行了
- @Controller:web层
- @Service:service层
- @Repository:dao层
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
- XML可以适用任何场景 ,结构清晰,维护方便
- 注解不是自己提供的类使用不了,开发简单方便
- xml管理Bean
- 注解完成属性注入
- 使用过程中, 可以不用扫描,扫描是为了类上的注解
- 进行注解驱动注册,从而使注解生效
- 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
- 如果不扫描包,就需要手动配置bean
- 如果不加注解驱动,则注入的值为null!