怎样建立自己的网站平台,电子商务网站的作用,万网上传wordpress,网站什么做文章目录7.Bean的自动装配自动装配说明测试环境搭建byName#xff08;按名称自动装配#xff09;测试byName运行机制小结#xff1a;byType#xff08;按类型自动装配#xff09;测试使用注解进行自动装配AutowiredQualifierResourceAutowired与Resource异同8.使用注解开发…
文章目录7.Bean的自动装配自动装配说明测试环境搭建byName按名称自动装配测试byName运行机制小结byType按类型自动装配测试使用注解进行自动装配AutowiredQualifierResourceAutowired与Resource异同8.使用注解开发ComponentBean的实现Value属性注入Component的衍生注解注解实现自动装配scope设置作用域注解开发小结9.使用Java的方式配置Spring10.代理模式静态代理静态代理角色分析代码实现加深理解静态代理与AOP的关系动态代理例子加深理解11.面向切面编程AOP什么是AOPAOP在Spring中的作用使用Spring实现Aop方式一通过 Spring API 实现方式二自定义类来实现AOP方式三使用注解实现12.整合Mybatis准备工作MyBatis-Spring学习Spring整合MyBatis方式一Spring整合MyBatis方式二13.声明式事务代码演示7.Bean的自动装配
自动装配说明
自动装配是使用spring满足bean依赖的一种方法。
spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制分别是
在xml中显式配置在java中显式配置隐式的bean发现机制和自动装配。
Spring的自动装配需要从两个角度来实现或者说是两个操作
组件扫描(component scanning)spring会自动发现应用上下文中所创建的bean自动装配(autowiring)spring自动满足bean之间的依赖也就是我们说的IoC/DI
组件扫描和自动装配组合发挥巨大威力使得显式的配置降低到最少。 在后面的开发中推荐不使用自动装配和xml配置 , 而使用注解 测试环境搭建
1.新建一个项目 2.新建两个实体类Cat和Dog。都有一个叫的方法
public class Cat {public void shout() {System.out.println(miao~);}
}public class Dog {public void shout() {System.out.println(wang~);}
}3.新建一个Person类
public class Person {private Cat cat;private Dog dog;private String pname;Overridepublic String toString() {return Person{ cat cat , dog dog , pname pname \ };}public void setCat(Cat cat) {this.cat cat;}public void setDog(Dog dog) {this.dog dog;}public void setPname(String pname) {this.pname pname;}public Cat getCat() {return cat;}public Dog getDog() {return dog;}public String getPname() {return pname;}
}4.编写Spring配置文件
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean iddog classpojo.Dog/bean idcat classpojo.Cat/bean idperson classpojo.Personproperty namecat refcat/property namedog refdog/property namepname value张三//bean
/beans5.测试 Testpublic void testMethodAutowire() {ApplicationContext context new ClassPathXmlApplicationContext(beans.xml);Person person context.getBean(person,Person.class);person.getCat().shout();person.getDog().shout();}如果测试没有问题进入下一步的学习
byName按名称自动装配
由于在手动配置xml过程中常常发生字母缺漏和大小写等错误而无法对其进行检查使得开发效率降低。
采用自动装配将避免这些错误并且使配置简单化。
测试
1、修改bean配置增加一个属性 autowire“byName” bean idperson classpojo.Person autowirebyNameproperty namepname value张三//bean2、再次测试结果依旧成功输出
3、我们将 cat 的bean id修改为 cat123
4、再次测试 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法真正的setCat就没执行对象就没有初始化所以调用时就会报空指针错误。
5、但如果将Person类下的方法setCat(Cat cat)改为setCat123(Cat cat)的话又能正常运行再次印证第4点说明
byName运行机制小结
当一个bean节点带有 autowire byName的属性时。
将查找其类中所有的set方法名例如setCat获得将set去掉并且首字母小写的字符串即cat。去spring容器中寻找是否有此字符串名称id的对象。如果有就取出注入如果没有就报空指针异常。
byType按类型自动装配
使用byType自动装配时首先需要保证同一类型的对象在spring容器中唯一。如果不唯一会报NoUniqueBeanDefinitionExceptionbean定义不唯一异常。
测试
1、将user的bean配置修改一下 autowire“byType” bean idperson classpojo.Person autowirebyTypeproperty namepname value张三//bean2、测试正常输出
3、在注册一个cat 的bean对象 bean iddog classpojo.Dog/bean idcat classpojo.Cat/bean idcat2 classpojo.Cat/4、测试报错NoUniqueBeanDefinitionException
5、删掉cat2将cat的bean名称改掉测试。 bean iddog classpojo.Dog/bean idcat123 classpojo.Cat/因为是按类型装配所以并不会报异常也不影响最后的结果。甚至将id属性去掉也不影响结果。 bean iddog classpojo.Dog/bean classpojo.Cat/这就是按照类型自动装配。
使用注解进行自动装配
jdk1.5开始支持注解spring2.5开始全面支持注解。可以利用注解的方式注入属性。
1、在spring配置文件中引入context文件头约束
xmlns:contexthttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd2、开启属性注解支持
context:annotation-config/完整模板
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdcontext:annotation-config//beansAutowired
该注解和下面的Qualifier注解属于org.springframework.beans.factory.annotation
Autowired是按类型自动转配的不支持id匹配。 需要导入 spring-aop的包 测试
1、将Person类中的set方法去掉使用Autowired注解
public class Person {Autowiredprivate Cat cat;Autowiredprivate Dog dog;private String pname;Overridepublic String toString() {return Person{ cat cat , dog dog , pname pname \ };}public void setPname(String pname) {this.pname pname;}public Cat getCat() {return cat;}public Dog getDog() {return dog;}
}此时配置文件内容因为是按类型自动装配的所以cat的bean id改为啥都行
...context:annotation-config/bean iddog classpojo.Dog/bean idcat123 classpojo.Cat/...2、测试成功运行
另外当Autowired(requiredfalse)对象可以为null 当Autowired(requiredtrue)对象必须存对象不能为null。
Qualifier
Autowired是根据类型自动装配的加上Qualifier则可以根据byName的方式自动装配 Qualifier不能单独使用。
测试实验步骤
1、配置文件修改内容保证类型存在对象。且名字不为类的默认名字 bean iddog1 classpojo.Dog/bean iddog2 classpojo.Dog/bean idcat1 classpojo.Cat/bean idcat2 classpojo.Cat/2、没有加Qualifier测试直接报错
3、在Person属性上添加Qualifier注解 AutowiredQualifier(value cat2)private Cat cat;AutowiredQualifier(value dog2)private Dog dog;4、测试成功输出
Resource
该注解属于javax.annotation的
Resource如有指定的name属性先按该属性进行byName方式查找装配其次再进行默认的byName方式进行装配如果以上都不成功则按byType的方式自动装配。都不成功则报异常。
实验测试 实验1使之既按名称查找也按类型查找 Resource(name cat2)private Cat cat;Resourceprivate Dog dog;bean iddog classpojo.Dog/bean idcat1 classpojo.Cat/bean idcat2 classpojo.Cat/成功输出结果
实验2使之按类型查找 bean iddog classpojo.Dog/bean idcat1 classpojo.Cat/Resourceprivate Cat cat;Resourceprivate Dog dog;同样成功输出结果
Autowired与Resource异同
1、Autowired与Resource都可以用来装配bean。都可以写在字段上或写在setter方法上。
2、Autowired默认按类型装配属于spring规范默认情况下必须要求依赖对象必须存在如果要允许null 值可以设置它的required属性为false如Autowired(requiredfalse) 如果我们想使用名称装配可以结合Qualifier注解进行使用
3、Resource默认按照名称进行装配名称可以通过name属性进行指定。如果没有指定name属性当注解写在字段上时默认取字段名进行按照名称查找如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是如果name属性一旦指定就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象但执行顺序不同。Autowired先byTypeResource先byName。
8.使用注解开发
在spring4之后必须要保证AOP的包导入 在配置文件当中还得要引入一个context约束
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd/beans配置扫描哪些包下的注解
!--指定注解扫描包--
context:component-scan base-packagepojo/ComponentBean的实现
Component意为组件该注解放在类上说明这个类被Spring管理了就是bean
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd!--指定注解扫描包--context:component-scan base-packagepojo//beansComponent
// 或者Component(user)
// 相当于配置文件中 bean iduser class当前注解的类/
public class User {public String name 张三;
}Testpublic void test(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(beans.xml);User user (User) applicationContext.getBean(user);System.out.println(user.name);}Value属性注入
1、可以不用提供set方法直接在直接名上添加value(“值”) Value(张三)// 相当于property namename value张三/public String name;2、如果提供了set方法也可以在set方法上添加value(“值”) Value(张三)// 相当于property namename value张三/public void setName(String name) {this.name name;}Component的衍生注解
Component有几个衍生注解我们在Web开发中会按照MVC三层架构进行分层
DAO层RepositoryService层ServiceController层Controller
这四个注解的功能是一样的都是代表将某个类注册到Spring中装配bean
注解实现自动装配
上面已讲解过
scope设置作用域
singleton默认的Spring会采用单例模式创建这个对象。关闭工厂 所有的对象都会销毁。prototype原型多例模式。关闭工厂 所有的对象不会销毁。内部的垃圾回收机制会回收
该注解放在类上
Controller(user)
Scope(prototype)
public class User {Value(张三)public String name;
}注解开发小结
XML与注解比较
XML可以适用任何场景 结构清晰维护方便注解不是自己提供的类使用不了开发简单方便
xml与注解整合开发 【推荐】 xml管理Bean 注解完成属性注入
作用
进行注解驱动注册context:annotation-config/从而使注解生效用于激活那些已经在spring容器里注册过的bean上面的注解也就是显式地向Spring注册如果不扫描包就需要手动配置bean如果不加注解驱动则注入的值为null
9.使用Java的方式配置Spring
即完全不使用xml配置
JavaConfig 原来是 Spring 的一个子项目它通过 Java 类的方式提供 Bean 的定义信息在 Spring4 的版本 JavaConfig 已正式成为 Spring4 的核心功能 。
测试
1、编写一个实体类Dog
Component //将这个类标注为Spring的一个组件放到容器中
public class Dog {public String name dog;
}2、新建一个config配置包编写一个MyConfig配置类
Bean 通过方法注册一个bean这里的返回值就Bean的类型方法名就是bean的id
Configuration //代表这是一个配置类
public class MyConfig {Bean //通过方法注册一个bean这里的返回值就Bean的类型方法名就是bean的idpublic Dog dog(){return new Dog();}
}3、测试
可以发现这里是通过new AnnotationConfigApplicationContext来读取Java配置类对比之前的new ClassPathXmlApplicationContext之前的是读取XML配置文件来获取ApplicationContext
Test
public void test2(){ApplicationContext applicationContext new AnnotationConfigApplicationContext(MyConfig.class);Dog dog (Dog) applicationContext.getBean(dog);System.out.println(dog.name);
}4、成功输出结果
如何导入其他配置类 1、我们再编写一个配置类
Configuration //代表这是一个配置类
public class MyConfig2 {
}2、在之前的配置类中我们来选择导入这个配置类
Configuration
Import(MyConfig2.class) //导入合并其他配置类类似于配置文件中的 inculde 标签
public class MyConfig {Beanpublic Dog dog(){return new Dog();}
}关于这种Java类的配置方式我们在之后的SpringBoot 和 SpringCloud中还会大量看到我们需要知道这些注解的作用即可
10.代理模式
为什么要学习代理模式因为AOP的底层机制就是动态代理【SpringAOP和SpringMVC】
代理模式包括静态代理和动态代理
学习AOP之前 , 我们要先了解一下代理模式
静态代理
以租房为例子
静态代理角色分析
抽象业务一般使用接口或者抽象类来实现真实角色被代理的角色代理角色代理真实角色代理真实角色后 , 一般会做一些附属的操作客户端使用代理角色来进行一些操作
代码实现
Rent接口 即租房这一抽象业务
//抽象角色租房
public interface Rent {void rent();
}Host 即真实角色: 房东房东要出租房子
//真实角色: 房东房东要出租房子
public class Host implements Rent{public void rent() {System.out.println(房屋出租);}
}Proxy 即代理角色中介
//代理角色中介
public class Proxy implements Rent {private Host host;public Proxy() { }public Proxy(Host host) {this.host host;}//租房public void rent(){seeHouse();host.rent();fee();}//看房public void seeHouse(){System.out.println(带房客看房);}//收中介费public void fee(){System.out.println(收中介费);}
}Client 即客户端
//客户类一般客户都会去找代理
public class Client {public static void main(String[] args) {//房东要租房Host host new Host();//中介帮助房东Proxy proxy new Proxy(host);//你去找中介proxy.rent();}
}静态代理的好处:
可以使得我们的真实角色更加纯粹不再去关注一些公共的事情公共的业务由代理来完成实现了业务的分工公共业务发生扩展时变得更加集中和方便
缺点 :
类多了多了代理类工作量变大了开发效率降低
我们想要静态代理的好处又不想要静态代理的缺点所以就有了动态代理
加深理解静态代理
1、创建一个抽象业务接口例如UserService比如平时做的业务抽象起来就是增删改查 UserService类似上一例子的租房业务
//抽象角色增删改查业务
public interface UserService {void add();void delete();void update();void query();
}2、我们需要一个真实对象来完成这些增删改查操作 真实对象完成增删改查操作的人UserServiceImpl类似上一例子的房东
//真实对象完成增删改查操作的人类似上一例子的房东
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 query() {System.out.println(查询了一个用户);}
}3、在创建代理角色之前先想一想现在我们需要增加一个日志功能怎么实现
思路1 在实现类上增加代码 【工作量大效率低下而且修改公司项目源代码是大忌】思路2使用代理来做能够不改变原来的业务情况下实现此功能就是最好的了
4、设置一个代理类进行代理并实现新增功能 UserServiceProxy相当于上一例子的房屋中介
//代理角色在这里面增加日志的实现
public class UserServiceProxy implements UserService {private UserServiceImpl userService;public void setUserService(UserServiceImpl userService) {this.userService userService;}public void add() {log(add);userService.add();}public void delete() {log(delete);userService.delete();}public void update() {log(update);userService.update();}public void query() {log(query);userService.query();}public void log(String msg){System.out.println([debug] 执行了msg方法);}
}5、测试访问类
public class Client {public static void main(String[] args) {//真实业务UserServiceImpl userService new UserServiceImpl();//代理类UserServiceProxy proxy new UserServiceProxy();//使用代理类实现日志功能proxy.setUserService(userService);proxy.add();}
}与AOP的关系
我们在不改变原来的代码的情况下实现了对原有功能的增强这是AOP中最核心的思想
聊聊AOP纵向开发横向开发
动态代理
动态代理的角色和静态代理的一样动态代理的代理类是动态生成的静态代理的代理类是我们提前写好的动态代理分为两类一类是基于接口动态代理一类是基于类的动态代理 基于接口的动态代理JDK动态代理 基于类的动态代理cglib 现在用的比较多的是 javassist 来生成动态代理 . 百度一下javassist 我们这里使用JDK的原生代码来实现其余的道理都是一样的
JDK的动态代理需要了解两个类
核心 : InvocationHandler 和 Proxy 打开JDK帮助文档看看
【InvocationHandler调用处理程序】
Object invoke(Object proxy, Method method, Object[] args);proxy 调用该方法的代理实例method 所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口它可以是代理类继承该方法的代理接口的父类接口。args包含的方法调用传递代理实例的参数值的对象的阵列
【Proxy : 代理】 动态代理类 以下简称为代理类 是一个实现在类创建时在运行时指定的接口列表的类具有如下所述的行为。 代理接口是由代理类实现的接口。 代理实例是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序对象它实现了接口InvocationHandler 。 通过其代理接口之一的代理实例上的方法调用将被分派到实例调用处理程序的invoke方法传递代理实例java.lang.reflect.Method被调用方法的java.lang.reflect.Method对象以及包含参数的类型Object Object的数组。 调用处理程序适当地处理编码方法调用并且返回的结果将作为方法在代理实例上调用的结果返回。 //生成代理类
public Object getProxy(){return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}例子
抽象业务和真实角色和之前的一样
Rent 即抽象业务
//抽象业务租房
public interface Rent {public void rent();
}Host 即真实角色
//真实角色: 房东房东要出租房子
public class Host implements Rent{public void rent() {System.out.println(房屋出租);}
}ProxyInvocationHandler 即代理角色
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);}// proxy代理类 method代理类的调用处理程序的方法对象// 处理代理实例上的方法调用并返回结果Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {seeHouse();//核心本质利用反射实现Object result method.invoke(target, args);fee();return result;}//看房public void seeHouse(){System.out.println(带房客看房);}//收中介费public void fee(){System.out.println(收中介费);}
}Client
//租客
public class Client {public static void main(String[] args) {//真实角色Host host new Host();//代理实例的调用处理程序ProxyInvocationHandler pih new ProxyInvocationHandler();pih.setTarget(host); //将真实角色放置进去Rent proxy (Rent)pih.getProxy(); //动态生成对应的代理类proxy.rent();}
}一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类代理的是接口
加深理解
我们来使用动态代理实现代理我们后面写的UserService
我们也可以编写一个通用的动态代理实现的类所有的代理对象设置为Object即可
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);}// proxy : 代理类// method : 代理类的调用处理程序的方法对象.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 methodName){System.out.println(执行了methodName方法);}}测试
public class Test {public static void main(String[] args) {//真实对象UserServiceImpl userService new UserServiceImpl();//代理对象的调用处理程序ProxyInvocationHandler pih new ProxyInvocationHandler();pih.setTarget(userService); //设置要代理的对象UserService proxy (UserService)pih.getProxy(); //动态生成代理类proxy.delete();}
}测试增删改查查看结果
动态代理的好处
静态代理有的它都有静态代理没有的它也有
可以使得我们的真实角色更加纯粹不再去关注一些公共的事情公共的业务由代理来完成实现了业务的分工公共业务发生扩展时变得更加集中和方便一个动态代理一般代理某一类业务一个动态代理可以代理多个类代理的是接口
11.面向切面编程AOP
什么是AOP
AOPAspect Oriented Programming意为面向切面编程通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续是软件开发中的一个热点也是Spring框架中的一个重要内容是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性同时提高了开发的效率。
AOP在Spring中的作用
提供声明式事务允许用户自定义切面
以下名词需要了解下
横切关注点跨越应用程序多个模块的方法或功能。即是与我们业务逻辑无关的但是我们需要关注的部分就是横切关注点。如日志安全缓存事务等等切面Aspect横切关注点 被模块化 的特殊对象。即它是一个类。通知Advice切面必须要完成的工作。即它是类中的一个方法。目标Target被通知对象。代理Proxy向目标对象应用通知之后创建的对象。切入点PointCut切面通知 执行的 “地点”的定义。连接点JointPoint与切入点匹配的执行点。 SpringAOP中通过Advice定义横切逻辑Spring中支持5种类型的Advice 即 AOP在 不改变原有代码的情况下去增加新的功能
使用Spring实现Aop
【重点】使用AOP织入需要导入一个依赖包
!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --
dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version
/dependency方式一通过 Spring API 实现
1、首先编写我们的业务接口和实现类
public interface UserService {public void add();public void delete();public void update();public void search();}public class UserServiceImpl implements UserService{Overridepublic void add() {System.out.println(增加用户);}Overridepublic void delete() {System.out.println(删除用户);}Overridepublic void update() {System.out.println(更新用户);}Overridepublic void search() {System.out.println(查询用户);}
}2、然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
public class Log implements MethodBeforeAdvice {//method : 要执行的目标对象的方法//args : 被调用的方法的参数//target : 目标对象Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println( target.getClass().getName() 的 method.getName() 方法被执行了);}
}public class AfterLog implements AfterReturningAdvice {//returnValue 返回值//method被调用的方法//args 被调用的方法的对象的参数//target 被调用的目标对象Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println(执行了 target.getClass().getName()的method.getName()方法,返回值returnValue);}
}3、最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd!--注册bean--bean iduserService classservice.UserServiceImpl/bean idlog classlog.Log/bean idafterLog classlog.AfterLog/!--aop的配置--aop:config!--切入点 expression:表达式匹配要执行的方法--aop:pointcut idpointcut expressionexecution(* service.UserServiceImpl.*(..))/!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--aop:advisor advice-reflog pointcut-refpointcut/aop:advisor advice-refafterLog pointcut-refpointcut//aop:config
/beans4、测试
public class MyTest {Testpublic void test(){ApplicationContext context new ClassPathXmlApplicationContext(beans.xml);UserService userService (UserService) context.getBean(userService);userService.search();}
}AOP的重要性 : 很重要。一定要理解其中的思路主要是思想的理解这一块 .
Spring的AOP就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理
方式二自定义类来实现AOP
目标业务类不变依旧是userServiceImpl
1、写我们自己的一个切入类
public class DiyPointcut {public void before(){System.out.println(---------方法执行前---------);}public void after(){System.out.println(---------方法执行后---------);}}2、去spring中配置记得注释掉前一个例子的配置
!--第二种方式自定义实现--
!--注册bean--
bean iddiy classdiy.DiyPointcut/!--aop的配置--
aop:config!--第二种方式使用AOP的标签实现--aop:aspect refdiyaop:pointcut iddiyPonitcut expressionexecution(* service.UserServiceImpl.*(..))/aop:before pointcut-refdiyPonitcut methodbefore/aop:after pointcut-refdiyPonitcut methodafter//aop:aspect
/aop:configexecution表达式 execution(* service.UserServiceImpl..*.*(..))
execution表达式主体第一个 *表达式返回值类型*号表示所有的类型 包名表示需要拦截的包名后面的两个句点表示当前包及其子包第二个*表示类名*表示所有类*(..)最后这个星号表示 方法名*表示所有方法后面括号表示 方法的参数两个句点表示所有参数
3、测试
public class MyTest {Testpublic void test(){ApplicationContext context new ClassPathXmlApplicationContext(beans.xml);UserService userService (UserService) context.getBean(userService);userService.add();}
}方式三使用注解实现
1、编写一个注解实现的增强类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;Aspect
public class AnnotationPointcut {Before(execution(* service.UserServiceImpl.*(..)))public void before(){System.out.println(---------方法执行前---------);}After(execution(* service.UserServiceImpl.*(..)))public void after(){System.out.println(---------方法执行后---------);}Around(execution(* service.UserServiceImpl.*(..)))//不常用public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println(环绕前);System.out.println(签名:jp.getSignature());//执行目标方法proceedObject proceed jp.proceed();System.out.println(环绕后);System.out.println(proceed);}
}2、在Spring配置文件中注册bean并增加支持注解的配置记得注释掉前面例子的配置
!--第三种方式:注解实现--
bean idannotationPointcut classdiy.AnnotationPointcut/
aop:aspectj-autoproxy/aop:aspectj-autoproxy /说明
通过aop命名空间的aop:aspectj-autoproxy /声明自动为spring容器中那些配置aspectJ切面的bean创建代理织入切面。当然spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作但具体实现的细节已经被aop:aspectj-autoproxy /隐藏起来了
aop:aspectj-autoproxy /有一个proxy-target-class属性默认为false表示使用jdk动态代理织入增强当配为aop:aspectj-autoproxy poxy-target-classtrue/时表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false如果目标类没有声明接口则spring将自动使用CGLib动态代理。
12.整合Mybatis
准备工作
1、导包配置Maven资源过滤
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdparentartifactIdspring-demo/artifactIdgroupIdorg.example/groupIdversion1.0-SNAPSHOT/version/parentmodelVersion4.0.0/modelVersionartifactIdspring-09-mybatis/artifactIddependenciesdependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.47/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion2.0.4/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-jdbc/artifactIdversion5.2.3.RELEASE/version/dependencydependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.2/version/dependencydependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.12/version/dependency/dependenciesbuildresourcesresourcedirectorysrc/main/resources/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includes/resourceresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringtrue/filtering/resource/resources/build/project2、实体类User
public class User {private int id; //idprivate String name; //姓名private String pwd; //密码Overridepublic String toString() {return User{ id id , name name \ , pwd pwd \ };}
}3、核心配置文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
configurationtypeAliasespackage namepojo//typeAliasesenvironments defaultdevelopmentenvironment iddevelopmenttransactionManager typeJDBC/dataSource typePOOLEDproperty namedriver valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/mybatis?userSSLtrueamp;useUnicodetrueamp;characterEncodingUTF8amp;serverTimezoneUTC/property nameusername valueroot/property namepassword value123456//dataSource/environment/environmentsmappersmapper resourceUserMapper.xml//mappers
/configuration4、UserDao接口编写
public interface UserMapper {ListUser selectUser();
}
5、接口对应的Mapper映射文件
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacedao.UserMapperselect idselectUser resultTypeUserselect * from user;/select/mapper6、测试
public class MyTest {Testpublic void selectUser() throws IOException {String resource mybatis-config.xml;InputStream inputStream Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession sqlSessionFactory.openSession(true);UserMapper mapper sqlSession.getMapper(UserMapper.class);ListUser userList mapper.selectUser();for (User user: userList){System.out.println(user);}sqlSession.close();}
}MyBatis-Spring学习
Spring整合MyBatis方式一
1、引入Spring配置文件Spring-dao.xml名字随便起最后导入到applicationContext.xml 测试中就可以直接这个applicationContext.xml
2、配置数据源替换mybaits的数据源 mybatis-config.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE configurationPUBLIC -//mybatis.org//DTD Config 3.0//ENhttp://mybatis.org/dtd/mybatis-3-config.dtd
configurationtypeAliasespackage namepojo//typeAliases!-- 此时不需要写环境配置Spring配置文件写了同理下面的绑定UserMapper.xml这里写了Spring配置文件里不用写--mappersmapper resourceUserMapper.xml//mappers
/configuration3、配置SqlSessionFactory关联MyBatis
4、注册sqlSessionTemplate关联sqlSessionFactory
Spring-dao.xml
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd!--DataSource 使用Spring的数据源替换Mybatis的配置--!--配置数据源可以使用第三方的也可使用Spring的 这里使用Spring提供的JDBC--bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSourceproperty namedriverClassName valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/jdbcstudy?serverTimezoneUTCamp;useUnicodetrueamp;characterEncodingutf8amp;useSSLtrue/property nameusername valueroot/property namepassword value123456//bean!--配置SqlSessionFactory--bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource /!--绑定Mybatis配置文件--property nameconfigLocation valueclasspath:mybatis-config.xml/!--这个property namemapperLocations valueclasspath:UserMapper.xml/不需要写因为上面那行绑定的mybatis-config.xml里面已经包含绑定了UserMapper.xml两种只能选其一种--/bean!--SqlSessionTemplate就是我们使用的sqlSession --bean idsqlSession classorg.mybatis.spring.SqlSessionTemplate!--只能使用构造器注入sqlSessionFactory因为它没有set方法--constructor-arg index0 refsqlSessionFactory//bean/beansapplicationContext.xml
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdimport resourcespring-dao.xml/bean iduserMapper classdao.UserMapperImplproperty namesqlSession refsqlSession//bean/beans5、增加Dao接口的实现类私有化sqlSessionTemplate
public class UserMapperImpl implements UserMapper{// 在原来我们所有操作都使用sqlSession来执行现在都使用sqlSessionTemplateprivate SqlSessionTemplate sqlSession;// 之前用习惯sqlSession故取名为sqlSessionpublic void setSqlSession(SqlSessionTemplate sqlSession) {this.sqlSession sqlSession;}public ListUser selectUser() {UserMapper mapper sqlSession.getMapper(UserMapper.class);return mapper.selectUser();}}
6、测试
public class MyTest {Testpublic void test2(){ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);UserMapper mapper (UserMapper) context.getBean(userMapper);ListUser user mapper.selectUser();System.out.println(user);}
}
Spring整合MyBatis方式二
mybatis-spring1.2.3版以上的才有这个 .
官方文档截图 : dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看
1、将我们上面写的UserMapperImpl修改一下
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {public ListUser selectUser() {UserMapper mapper getSqlSession().getMapper(UserMapper.class);return mapper.selectUser();}
}2、修改bean的注册 bean iduserMapper2 classdao.UserMapperImpl2property namesqlSessionFactory refsqlSessionFactory//bean3、测试 Testpublic void test3(){ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);UserMapper mapper (UserMapper) context.getBean(userMapper2);ListUser user mapper.selectUser();System.out.println(user);}13.声明式事务 要么都成功要么都失败 事务的ACID原则
原子性一致性隔离性 多个业务可能操作一个资源防止数据损坏持久性 事务一旦提交无论系统发生什么问题结果都不会被影响。
Spring中的事务管理
声明式事务AOP的一个应用交由容器管理编程式事务 代码演示
spring-dao.xml 需要导入tx约束
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:txhttp://www.springframework.org/schema/txxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttps://www.springframework.org/schema/tx/spring-tx.xsd!--DataSource 使用Spring的数据源替换Mybatis的配置--!--配置数据源可以使用第三方的也可使用Spring的 这里使用Spring提供的JDBC--bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSourceproperty namedriverClassName valuecom.mysql.cj.jdbc.Driver/property nameurl valuejdbc:mysql://localhost:3306/jdbcstudy?serverTimezoneUTCamp;useUnicodetrueamp;characterEncodingutf8amp;useSSLtrue/property nameusername valueroot/property namepassword value123456//bean!--配置SqlSessionFactory--bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource /!--绑定Mybatis配置文件--property nameconfigLocation valueclasspath:mybatis-config.xml/!--这个property namemapperLocations valueclasspath:UserMapper.xml/不需要写因为上面那行绑定的mybatis-config.xml里面已经包含绑定了UserMapper.xml两种只能选其一种--/bean!--SqlSessionTemplate就是我们使用的sqlSession --bean idsqlSession classorg.mybatis.spring.SqlSessionTemplate!--只能使用构造器注入sqlSessionFactory因为它没有set方法--constructor-arg index0 refsqlSessionFactory//bean!-- --!--配置声明式事务--bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerconstructor-arg refdataSource //bean!--结合AOP实现事务织入--!--配置事务通知--tx:advice idtxAdvice transaction-managertransactionManager!--给哪些方法配置事务--!--配置事务的传播propagation特性--tx:attributestx:method nameadd propagationREQUIRED/tx:method namedelete propagationREQUIRED/tx:method nameupdate propagationREQUIRED/tx:method name* propagationREQUIRED/tx:method namequery read-onlytrue//tx:attributes/tx:advice!--配置事务切入--aop:configaop:pointcut idtxpointxut expressionexecution(* dao.*.*(..))/aop:advisor advice-reftxAdvice pointcut-reftxpointxut//aop:config
/beansapplicationContext.xml
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdimport resourcespring-dao.xml/bean iduserMapper classdao.UserMapperImplproperty namesqlSessionFactory refsqlSessionFactory/property/bean/beansUserMapper接口
public interface UserMapper {ListUser selectUser();// 添加一个用户int addUser(User user);// 删除一个用户int deleteUser(int id);
}
UserMapper.xml
?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacedao.UserMapperselect idselectUser resultTypeUserselect * from mybatis.user;/selectinsert idaddUser parameterTypeuserinsert into mybatis.user (id, name, pwd) values(#{id}, #{name}, #{pwd});/insertdelete iddeleteUser parameterTypeintdelete from mybatis.user where id#{id};/delete/mapperUserMapper实现类UserMapperImpl
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {public ListUser selectUser() {User user new User(10, 王五123, 213123);SqlSession sqlSession getSqlSession();UserMapper mapper sqlSession.getMapper(UserMapper.class);mapper.addUser(user);mapper.deleteUser(6);return mapper.selectUser();}public int addUser(User user) {return getSqlSession().getMapper(UserMapper.class).addUser(user);}Overridepublic int deleteUser(int id) {return getSqlSession().getMapper(UserMapper.class).deleteUser(id);}}测试 Testpublic void test(){ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);UserMapper mapper context.getBean(userMapper,UserMapper.class);ListUser userList mapper.selectUser();for(User user:userList){System.out.println(user);}}为什么需要配置事务
如果不配置就需要我们手动提交控制事务事务在项目开发过程非常重要涉及到数据的一致性的问题不容马虎