看完B站狂神的视频,小编获益匪浅,在学习途中记下了这篇文章
小伙伴也可以从B站获取狂神的完整视频哦!
狂神B站主页
Spring:春天------>给软件行业带来了春天!
2002,首次推出了Spring框架的雏形:interface21框架!
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日发布了1.0正式版。
Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
SSH:Struct2 + Spring + Hibernate!
SSM:SpringMVC + Spring + Mybatis!
官网:https://spring.io/projects/spring-framework#overview
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub:https://github.com/spring-projects/spring-framework
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.9version>
dependency>
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
现代化的Java开发!说白就是基于Spring的开发!
Spring Boot
一个快速开发的脚手架。
基于SpringBoot可以快速的开发单个微服务。
约定大于配置。
Spring Cloud
SpringCloud是基于SpringBoot实现的。
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!
弊端:发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!”
我们先用我们原来的方式写一段代码
DaoUser接口
public interface DaoUser {
/**
* 输出语句测试
* */
public void printText();
}
DaoUser的实现类DaoUserMyBatisImpl
public class DaoUserMyBatisImpl implements DaoUser{
@Override
public void printText() {
System.out.println("我是MyBatis的执行!");
}
}
ServiceUser接口
public interface ServiceUser {
/**
* 输出打印特定的语句
* */
public void printText();
}
ServiceUser的实现类
public class ServiceUserImpl implements ServiceUser{
private DaoUser daoUser = new DaoUserMyBatisImpl();
@Override
public void printText() {
daoUser.printText();
}
}
用UserPrintText测试
public class UserPrintText {
@Test
public void UserPrintTextTest(){
new ServiceUserImpl().printText();
}
}
这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下
把Userdao的实现类增加一个
public class DaoUserJdbcImpl implements DaoUser{
@Override
public void printText() {
System.out.println("我是Jdbc的执行!");
}
}
紧接着我们要去使用DaoUserJdbcImpl的话 , 我们就需要去service实现类里面修改对应的实现
private DaoUser daoUser = new DaoUserJdbcImpl();
每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身
所有我们采用IOC的解决办法
让UserDao的具体调用在Service层,在Service层设置一个setUserDao的接口,让我们的Controller层去实现
/**
* 实现我们DaoUser的Service层的自我调用
* @param daoUser 即将设置的UserDao实现类的对象
* */
public void setDaoUser(DaoUser daoUser);
private DaoUser daoUser ;
@Override
public void setDaoUser(DaoUser daoUser) {
this.daoUser = daoUser;
}
那么Cotroller层才是控制的主人公
@Test
public void UserPrintTextTest(){
ServiceUserImpl service = new ServiceUserImpl();
service.setDaoUser(new DaoUserMyBatisImpl());
service.printText();
}
我认为IOC(控制反转),就是获得依赖对象的方式反转了,以前是Service层进行调用,现在是Controller进行自定义的设置。Controller层就是来处理用户请求的,如果有个用户,有个按钮来控制使用的是JDBC还是MyBatis,那么通过IOC可以非常轻松的实现
控制反转IOC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H0DhMNnS-1631336112019)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210805143707321.png)]
IOC是Spring框架的核心内容,采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection,DI)。
Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。
编写Pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hello {
private String str;
}
编写beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.ZhengXinhao.Pojo.Hello">
<property name="str" value="Spring"/>
bean>
beans>
测试
@Test
public void HelloTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
思考
Hello 对象是谁创建的 ?
hello 对象是由Spring创建的
Hello 对象的属性是怎么设置的 ?
hello 对象的属性是由Spring容器设置的
这个过程就叫控制反转 :
依赖注入 : 就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码
而我理解的通过xml配置实现IOC的工作流程就是,我们把我们对每个类的配置情况写在beans.xml中交个Spring,在创建我们的ApplicationContext的时候,其实我们的每一个bean对象都被创建放在了我们的Spring中的BeanFactory中了,每一次的getBeans只是从里面调用而已,对象没有改变(它的hashcode没有改变)。所谓的IOC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !
set方法注入是调用无参构器的,如果我们自定义了一个有参构造器,就会报错
我们也可以用有参构造来创建
下标法
<constructor-arg index="0" value="Hello Java Designer!"/>
属性法
<constructor-arg type="java.lang.String" value="Hello Java Designer!"/>
引用名法 本人最青睐
<constructor-arg name="str" value="Hello Java Designer!"/>
给你的对象引用名起别名,原来的名字依然可以使用
<alias name="hello" alias="helloNew"/>
name里面的别名,分割方式有很多种
<bean id="userT" class="com.kuang.pojo.UserT" name="user2 u2,u3;u4">
<property name="name" value="郑信豪"/>
bean>
这个import。一般用于团队开发使用,它可以将多个配置文件,导入合并为一个。
也就是是说导入其他的beans.xml就不用在程序代码在再去添加了
new ClassPathXmlApplicationContext("beans.xml","bean1.xml","bean2.xml","bean3.xml");
beans.xml(applicationContext.xml)中直接导入
<import resource="bean1.xml"/>
<import resource="bean2.xml"/>
<import resource="bean3.xml"/>
导入之后里面的东西会被整合
前面已经说过了
通过查找name值的set方法,这里严格检查字母的大小写
引用类型
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
待注入对象
public class Student {
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;
}
<bean id="address" class="com.ZhengXinhao.Pojo.Address">
<property name="address" value="重庆邮电大学"/>
bean>
<bean id="student" class="com.ZhengXinhao.Pojo.Student">
<property name="name" value="郑信豪"/>
<property name="address">
<bean class="com.ZhengXinhao.Pojo.Address">
<property name="address" value="重庆"/>
bean>
property>
<property name="books">
<array>
<value>MySqlvalue>
<value>Javavalue>
array>
property>
<property name="hobbies">
<list>
<value>打游戏value>
<value>学习value>
list>
property>
<property name="games">
<set>
<value>王者荣耀value>
<value>LOLvalue>
set>
property>
<property name="card">
<map>
<entry key="student" value="2019212911"/>
<entry key="phone" value="17382215131"/>
<entry key="null" value=""/>
map>
property>
<property name="wife">
<null/>
property>
<property name="info">
<props>
<prop key="sex">男prop>
<prop key="age">21prop>
props>
property>
bean>
我们可以使用p命名空间和c命名空间进行注入
使用:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.kuang.pojo.User" p:name="郑信豪" p:age="20"/>
<bean id="user2" class="com.kuang.pojo.User" c:name="狂神" c:age="22"/>
beans>
<bean id="student" class="com.ZhengXinhao.Pojo.Student" p:address-ref="address">
特别注意,需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
<bean id="user2" class="com.kuang.pojo.User" c:name="狂神" c:age="22" scope="singleton"/>
<bean id="user2" class="com.kuang.pojo.User" c:name="狂神" c:age="22" scope="prototype"/>
创建项目,一个人有两个宠物!
public class People {
private String name;
private Cat cat;
private Dog dog;
}
public class Cat {
public void shot(){
System.out.println("miao~");
}
}
public class Dog {
public void shot(){
System.out.println("wang~");
}
}
装配autowire=“byName”
<bean id="people" class="com.ZhengXinhao.Pojo.People" p:name="郑信豪" autowire="byName"/>
<bean id="dog" class="com.ZhengXinhao.Pojo.Dog"/>
<bean id="cat" class="com.ZhengXinhao.Pojo.Cat"/>
也可以
<bean id="people" class="com.ZhengXinhao.Pojo.People" p:name="郑信豪" autowire="byType"/>
<bean id="dog" class="com.ZhengXinhao.Pojo.Dog"/>
<bean id="cat" class="com.ZhengXinhao.Pojo.Cat"/>
检查大小写
jdk1.5支持的注解,Spring2.5就支持注解了!
要使用注解须知:
配置注解的支持
<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,同类型有多个就会再次byName!
@Nullable
字段标记了了这个注解,说明这个字段可以为null
当然我们也可以使用@Autowired(required = false),里面的required默认为true
@Qualifier
当类型重复了且找不到byName的值,就通过@Qualifier进行匹配
@Resource
在jdk11中已经取消
默认byType,同类型有多个就会再次byName!
在Spring4之后,要使用注解开发,必须要保证aop的包导入了
使用注解需要导入约束,配置注解的支持!
配置注解的支持
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.ZhengXinhao.Pojo"/>
beans>
@Component(“address”)
注册bean,默认id为类名首字母小写
表明这个类要作为组件类,并且告诉Spring要为它注册bean
#就是等同于
<bean id="address" class="com.ZhengXinhao.Pojo.Address">
也可以等同于
@Bean("address")
public UserServiceImpl getService(){
return new UserServiceImpl();
}
@Value
字段属性的注入
@Value("ZhengXinHao")
private String name;
@Component衍生注解
dao 【@Repository】
service 【@Service】
controller 【@Controller】
这三个和@Component一样
@Scope(“singleton”)
设置作用域
小结
我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能!
@Data
@Component
public class Address {
@Value("重庆邮电大学")
private String address;
}
@Data
@Component
public class Student {
@Value("郑信豪")
private String name;
@Autowired
private Address address;
}
/**
* @author lenovo
* .这个也会被注册到容器中,因为他本来就是一个@Component
* .@Configuration代表这是一个配置类,就和我们之前看的beans.xml一样的
* .@ComponentScan("com.ZhengXinhao.Pojo")扫描这个包的注解
* .@Import(JavaConfig2.class)引入其他的配置文件(JavaConfig)
*/
@Import(JavaConfig2.class)
@Configuration
@ComponentScan("com.ZhengXinhao.Pojo")
public class JavaConfig {
@Bean("student")
public Student get_student(){
return new Student();
}
}
测试
@Test
public void javaConfigTest(){
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
Student student = context.getBean("student", Student.class);
System.out.println(student);
}
@Data
@Component
public class Address {
@Value("重庆邮电大学")
private String address;
}
@Data
@Component
public class Student {
private String name;
@Autowired
private Address address;
public Student(String name) {
this.name = name;
}
}
@Configuration
@ComponentScan("com.ZhengXinhao.Pojo")
public class JavaConfig {
@Bean("student")
public Student get_Student(){
return new Student("郑信豪");
}
}
测试
@Test
public void JavaConfigTest(){
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
Student student = (Student) context.getBean("student");
System.out.println(student);
}
为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP和SpringMVC】
代理模式的分类:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sPr0Tyij-1631336112025)(E:\学习文件\JAVA学习\学习记录\前端\imgs\image-20210808152824555.png)]
角色分析:
抽象角色(出租,结婚)
public interface Rent {
/**
* 出租房子的功能
* */
public void rent();
}
真实对象(房东,结婚对象)
public class Hostess implements Rent{
@Override
public void rent() {
System.out.println("出租房屋,收钱!");
}
}
代理对象(房屋中介,婚介所)
public class Proxy implements Rent{
private Hostess hostess;
public Proxy(Hostess hostess) {
this.hostess = hostess;
}
@Override
public void rent() {
hostess.rent();
seeHouse();
sign();
fee();
}
//看房
private void seeHouse(){
System.out.println("中介带着看房子!");
}
//签合同
private void sign(){
System.out.println("和中介签署租赁合同!");
}
//收费用
private void fee(){
System.out.println("中介收取费用!");
}
}
客户(你)
public class Client {
@Test
public void client(){
Hostess hostess = new Hostess();
Proxy proxy = new Proxy(hostess);
proxy.rent();
}
}
代理模式的好处:
可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
公共角色就交给代理角色!实现了业务的分工!
公共业务发生扩展的时候,方便集中管理!
实现开闭原则:软件实体应当对扩展开放,对修改关闭
缺点:
抽象角色(出租,结婚)
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
真实对象(房东,结婚对象)
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加了一个用户!");
}
@Override
public void delete() {
System.out.println("删除了一个用户!");
}
@Override
public void update() {
System.out.println("修改了一个用户!");
}
@Override
public void query() {
System.out.println("查询了一个用户!");
}
}
代理对象(房屋中介,婚介所)
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("[Debug] 使用了一个"+msg+"方法");
}
}
客户(你)
public class Client {
@Test
public void Test(){
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.delete();
}
}
从代理到AOP
动态代理和静态代理角色一样
动态代理的代理类是动态生成的,不是我们直接写好的!
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
需要了解两个类:Proxy:生成动态代理实例;InvocationHandler:调用处理程序,并返回结果
抽象对象
public interface Rent {
/**
* 出租房屋的能力
* */
public void rent();
}
真实对象
public class Hostess implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
动态生成代理对象的类
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);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质,就是使用反射机制实现!
Object result = method.invoke(rent, args);
seeHose();
fee();
return result;
}
public void seeHose(){
System.out.println("中介带着看房子!");
}
public void fee(){
System.out.println("中介收取费用!");
}
}
测试
@Test
public void Test(){
//真实角色
Hostess hostess = new Hostess();
//代理角色:现在没有
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象!
pih.setRent(hostess);
Rent proxy = (Rent) pih.getProxy(); //这里的proxy就是动态生成的,我们并没有写
proxy.rent();
System.out.println(Hostess.class.getInterfaces()[0].getName());
}
我们可以生成工具类
public class ProxyTarget implements InvocationHandler {
private Object target;
public ProxyTarget(Object target) {
this.target = target;
}
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"方法已经执行");
return method.invoke(target, args);
}
}
测试
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
ProxyTarget target = new ProxyTarget(service);
UserService proxy = (UserService) target.getProxy();
proxy.add();
}
动态代理的好处:
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续
,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ngDzNtwW-1631336112028)(E:\学习文件\JAVA学习\学习记录\前端\imgs\image-20210809160633114.png)]
提供声明式事务;允许用户自定义切面
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
切面
(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
通知
(Advice):切面必须要完成的工作。即,它是类中的一个方法。
目标(Target):被通知对象。
代理(Proxy):向目标对象应用通知之后创建的对象。
切入点
(PointCut):切面通知执行的“地点”的定义。
连接点(JointPoint):与切入点匹配的执行点。
切入点(Pointcut)
在哪些类,哪些方法上切入(where)
通知(Advice)
在方法执行的什么实际(**when:**方法前/方法后/方法前后)做什么(**what:**增强的功能)
切面(Aspect)
切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
即AOP在不改变原有代码的情况下,去增加新的功能。
导入依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.7version>
dependency>
使用Spring的API接口【主要是SpringAPI接口实现】
核心业务接口
public interface UserService {
public void add();
public void delete();
public String update();
public void query();
}
核心业务实现类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户!");
}
@Override
public void delete() {
System.out.println("删除了一个用户!");
}
@Override
public String update() {
System.out.println("修改了一个用户!");
return "Hello Java Designer!";
}
@Override
public void query() {
System.out.println("查询了一个用户!");
}
}
切面
public class AfterLog implements AfterReturningAdvice{
/**
* @param method 要执行的目标对象的方法
* @param args 参数
* @param target 目标对象
* @param returnValue 方法的返回值
* */
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+"方法被执行,返回值为--->"+"("+returnValue.getClass().getTypeName()+")"+returnValue);
}
}
public class BeforeLog implements MethodBeforeAdvice {
/**
* @param method 要执行的目标对象的方法
* @param args 参数
* @param target 目标对象
* */
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法即将被执行");
}
}
xml配置
expression:表达式,execution(要执行的位置!* * * * *)
配置原则
<bean id="SService" class="com.ZhengXinhao.Service.UserService" abstract="true"/>
<bean id="service" class="com.ZhengXinhao.Service.UserServiceImpl"/>
<bean id="after" class="com.ZhengXinhao.Log.AfterLog"/>
<bean id="before" class="com.ZhengXinhao.Log.BeforeLog"/>
<aop:config>
<aop:pointcut id="LogPointCut" expression="execution(* com.ZhengXinhao.Service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="after" pointcut-ref="LogPointCut"/>
<aop:advisor advice-ref="before" pointcut-ref="LogPointCut"/>
aop:config>
测试
@Test
public void AopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService) context.getBean("service");
service.update();
}
自定义类来实现【主要是切面定义】
自定义方法
public class DiyAspect {
public void before(){
System.out.println("=======方法即将被执行========");
}
public void after(){
System.out.println("==========方法执行后========");
}
}
beans.xml
<bean id="SService" class="com.ZhengXinhao.Service.UserService" abstract="true"/>
<bean id="service" class="com.ZhengXinhao.Service.UserServiceImpl"/>
<bean id="diyAspect" class="com.ZhengXinhao.Diy.DiyAspect"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.ZhengXinhao.Service.UserServiceImpl.*(..))"/>
<aop:aspect ref="diyAspect">
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
aop:aspect>
aop:config>
测试
@Test
public void AopTest(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService) context.getBean("service");
service.update();
}
接口
public interface UserService {
public void add();
public void delete();
public String update();
public void query();
}
实现类
@Component("service")
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户!");
}
@Override
public void delete() {
System.out.println("删除了一个用户!");
}
@Override
public String update() {
System.out.println("修改了一个用户!");
return "Hello Java Designer!";
}
@Override
public void query() {
System.out.println("查询了一个用户!");
}
}
切面
@Aspect
@Component
public class AnnotationPointCut {
@Before("execution(* com.ZhengXinhao.Service.UserServiceImpl.*(..))")
public void before(){
System.out.println("====方法执行前====");
}
@After("execution(* com.ZhengXinhao.Service.UserServiceImpl.*(..))")
public void after(){
System.out.println("====方法执行后====");
}
@Around("execution(* com.ZhengXinhao.Service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前");
System.out.println(joinPoint.getSignature());
joinPoint.proceed();
System.out.println("环绕后");
}
}
配置JavaConfig
@Configuration
@ComponentScan("com.ZhengXinhao")
@EnableAspectJAutoProxy
public class JavaConfig {
}
注意
在注解配置中要用
@EnableAspectJAutoProxy
在xml配置中要用
<aop:aspectj-autoproxy/>
http://mybatis.org/spring/zh/
除了Sping和MyBatis必要的包以外,我们还要导入MyBatis-Spring的整合包
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.13version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.7version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
配置mybatis-config.xml
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
configuration>
配置spring-mybatis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置dataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/k_study?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterRnCoding=utf8"/>
<property name="password" value="123456"/>
<property name="username" value="root"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<!-- 配置sqlSessionFactory,导入原来的mysql-config.xml(dataSource、config、mapper)-->
<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/ZhengXinhao/Mapper/BlogMapper.xml"/>
</bean>
<!-- 配置sqlSession,只能用sqlSession的构造方法导入sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
配置接口
public interface BlogMapper {
public ArrayList<Blog> selectBlogs();
}
配置接口的Mybatis的对应的Mapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ZhengXinhao.Mapper.BlogMapper">
<select id="selectBlogs" resultType="com.ZhengXinhao.Pojo.Blog">
select * from k_study.blog
select>
mapper>
配置实现类让Spring托管
public class BlogMapperImpl implements BlogMapper{
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public ArrayList<Blog> selectBlogs() {
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
return mapper.selectBlogs();
}
}
配置总的beans配置xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-mybatis.xml"/>
<bean id="blogMapperImpl" class="com.ZhengXinhao.Mapper.BlogMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
<bean id="method2" class="com.ZhengXinhao.Mapper.BlogMapperImplExtend">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
beans>
测试
@Test
public void MyBatisReviewTest() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applacation.xml");
BlogMapper mapper = (BlogMapper) context.getBean("method2");
ArrayList<Blog> blogs = mapper.selectBlogs();
for (Blog blog : blogs) {
System.out.println(blog);
}
}
在上面的获得sqlSession的方法有不同的的实现方法,第一种就是手动的注入sqlSession,第二种就是继承sqlSessionDaoSupport
public class BlogMapperImplExtend extends SqlSessionDaoSupport implements BlogMapper{ @Override public ArrayList<Blog> selectBlogs() { return getSqlSession().getMapper(BlogMapper.class).selectBlogs(); } }
依然是交给Spring-MyBatis来管理
接口
public interface BlogMapper {
/**
* 查询所有的博客信息
* @return 返回Blog对象的集合
* */
public ArrayList<Blog> selectBlogs();
/**
* 删除用户
* @param id 删除依据
* */
public void delete(String id);
/**
*添加用户
* @param blog 准备添加的用户
* */
public void add(Blog blog);
}
实现类,需要被Spring托管
@Component("impl")
public class BlogMapperImpl implements BlogMapper{
@Autowired
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public ArrayList<Blog> selectBlogs() {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Blog blog = (Blog) context.getBean("blog");
add(blog);
delete("500");
int i =1/0;//定义一个错误,让程序有异常
return sqlSession.getMapper(BlogMapper.class).selectBlogs();
}
@Override
public void delete(String id) {
sqlSession.getMapper(BlogMapper.class).delete(id);
}
@Override
public void add(Blog blog) {
sqlSession.getMapper(BlogMapper.class).add(blog);
}
}
这样的话,这就不是一个事务
优化
在beans.xml中配置
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="transaction" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="TransactionPointCut" expression="execution(* com.ZhengXinhao.Mapper.BlogMapperImpl.*(..))"/>
<aop:advisor advice-ref="transaction" pointcut-ref="TransactionPointCut"/>
aop:config>
可以配置事务的执行路径
<tx:method name="select*" propagation="REQUIRED"/>
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。
Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。
就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!
思考:
为什么需要事务?
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8maven.compiler.encoding>
<java.version>11java.version>
<maven.compiler.source>11maven.compiler.source>
<maven.compiler.target>11maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.16version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.7version>
dependency>
dependencies>
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
<include>**/*.tldinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
<include>**/*.tldinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.22.1version>
<configuration>
<skipTests>trueskipTests>
configuration>
plugin>
plugins>
build>
<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.ZhengXinhao.Pojo.Hello">
<property name="str" value="Spring"/>
bean>
beans>
singleton
prototype
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.13version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.13version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.7version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.3.9version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.7version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.6version>
dependency>
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
configuration>
<?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">
<!-- 配置dataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/k_study?serverTimezone=GMT%2B8&useUnicode=true&useSSL=false&characterRnCoding=utf8"/>
<property name="password" value="123456"/>
<property name="username" value="root"/>
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
</bean>
<!-- 配置sqlSessionFactory,导入原来的mysql-config.xml(dataSource、config、mapper)-->
<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/ZhengXinhao/Mapper/BlogMapper.xml"/>
</bean>
<!-- 配置sqlSession,只能用sqlSession的构造方法导入sqlSessionFactory-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
</beans>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ZhengXinhao.Mapper.BlogMapper">
<select id="selectBlogs" resultType="com.ZhengXinhao.Pojo.Blog">
select * from k_study.blog
select>
mapper>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="spring-mybatis.xml"/>
<bean id="blogMapperImpl" class="com.ZhengXinhao.Mapper.BlogMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
bean>
<bean id="method2" class="com.ZhengXinhao.Mapper.BlogMapperImplExtend">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
beans>