· Spring的官方网站:https://spring.io/
· Maven仓库的官方网站http://mvnrepository.com/
· 主要学习framewrok核心框架
· 主要学习:https://docs.spring.io/spring/docs/5.1.7.RELEASE/spring-framework-reference/core.html#spring-core
1. 1 Spring框架特征
1. Spring是开源轻量级企业级Java应用程序开发框架
2. IoC(Inversion of Control):控制反转
方便解耦,简化开发,利用Ioc容器,避免硬编码造成的过度耦合 如:[类之间的关系:关联、泛化、依赖【聚合、组合】、继承、实现]
不采用Spring框架,传统的方法:Person类 Person per = new Person();由程序员来实现
采用Spring框架:利用Ioc容器将person对象传给你,不在是硬编码写在java代码里面,不再由程序员来实现,由Spring容器来实现,即是控制反转
3. AOP(Aspect Oriented Programming):面向切面编程
传统的数据库调用userDao->DB getUserInfo()、insertUser()、updateUser()需要记录日志,权限的处理方式
参考过滤器Filter的做法:在执行这些私人信息化的方法时,一切的日志记录、权限处理等都做成一个切面,在执行此类方法之前、之后、或者之后执行这个AOP切换
4. 声明式事物的支持,可以进行灵活的进行事务的管理
5. 方便程序的测试,Spring对Junit4的支持,可以通过注解方便的测试Spring程序
6. 降低了Java EE API的使用难度,Spring大大降低了对Servlet的依赖
7. 框架--Spring可以将简单的组件配置、组合成为复杂的应用
1. 2 Spring框架优势
1. 低侵入式设计,代码污染极低
2. 独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write Once,Run Anywhere的(一次编写,到处使用)
3. 【区别】Ioc控制反转--先去DI(Injection)依赖注入 + DL(Lookup)依赖查找
4. Spring的AOP支持允许将一些通用的任务如安全、事务、日志等进行集中式的管理,从而提供更好的复用.
5. Spring的ORM和DAO提供了与第三方持久层框架的良好整合,并简化了底层数据库的访问
6. Spring并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部(如同Vue框架--是渐进式的--可以局部使用也可以完全使用)
1. 3 Spring框架体系结构
1. Spring体系结构包含:核心容器(Core Container)、AOP(Aspect Oriented Programming)、设备支持(Instrmentation)、数据访问及集成(Data Access/Integeration)、Web、报文发送(Messaging)、Test六个模块集合中
2. 核心容器由:Spring-beans、Spring-core、Spring-context和Spring-expression(Spring Expression Language,SpEL)4个模块组成
3. AOP和设备支持由Spring-aop、Spring-aspects、Spring-instrument三个模块组成
4. 数据访问及集成:由Spring-jbdc、Spring-tx、Spring-orm、spring-jms和Spring-oxm五个模块组成
5. Web中Spring-web、Spring-webmvc、Spring-websocket和Spring-webflux四个模块组成
6. 报文发送:即Spring-messaging模块
7. Test:即Spring-test模块
2. 1 新建一个Spring工程
2. 2 查看项目工程目录
2. 3 配置pom.xml文件,添加依赖
https://mvnrepository.com/artifact/org.springframework/spring-core/5.1.5.RELEASE
https://mvnrepository.com/artifact/org.springframework/spring-context/5.1.5.RELEASE
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.neuedu.demogroupId>
<artifactId>springtestartifactId>
<version>0.0.1-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.1.5.RELEASEversion>
dependency>
dependencies>
project>
2.4 创建实体类Person.java
package com.neuedu.springtest.entity;
import java.util.List;
import java.util.Map;
/**
* @author 时万绘 定义学生实体类Student
*/
public class Student {
private Integer stuNo;
private String stuName;
private String gender;
private String birthday;
private List<String> friends;
private Map<String, Integer> scores;
private StuClass stuClass;
public Integer getStuNo() {
return stuNo;
}
public void setStuNo(Integer stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public Map<String, Integer> getScores() {
return scores;
}
public void setScores(Map<String, Integer> scores) {
this.scores = scores;
}
public StuClass getStuClass() {
return stuClass;
}
public void setStuClass(StuClass stuClass) {
this.stuClass = stuClass;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + ", gender="
+ gender + ", birthday=" + birthday + "]";
}
public Student(Integer stuNo, String stuName, String gender, String birthday,
List<String> friends, Map<String, Integer> scores, StuClass stuClass) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
this.friends = friends;
this.scores = scores;
this.stuClass = stuClass;
}
public Student() {
super();
}
public Student(Integer stuNo, String stuName, String gender, String birthday,
List<String> friends) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
this.friends = friends;
}
public Student(Integer stuNo, String stuName, String gender, String birthday) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
}
}
2.5 创建spring-ioc.xml文件 2.6 创建测试类文件TestSpring.java 3.1 新建一个spring-ioc.xml 3.2 新建一个测试类TestStudent.java 4.1 新建Student实体类、StuClass实体类、Course实体类 4.1.2 新建StuClass实体类 4.1.3 新建Course实体类 4.2 新建一个spring-ioc.xml 4.3 新建一个测试类TestStudentWithMulti.java @Scope(singleton)-- 默认单例模式 @Repository注解加在数据库操作的实现类上 JUit和Spring-test的网址: 添加依赖: 添加bean的xmlns:p
网址搜索
<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="person" class="com.neuedu.springtest.entity.Person">
bean>
beans>
package com.neuedu.springtest.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.neuedu.springtest.entity.Person;
/**
* @author 时万绘
*
*/
public class TestSpring {
public static void main(String[] args){
// 没有Spring时新建一个类对象的做法
// Person person = new Person();
// person.setCardNo("320921199xxxxx");
// System.out.println(person);
// 利用Spring框架新建一个类对象的做法
// 加载spring容器,解析指定的xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
// 从spring容器中获取指定类型的对象(指定名称的bean)
Person person = (Person) context.getBean("person");
System.out.println(person == null);
}
}
三、使用Spring的DI(Depedency Injection)核心技术注入属性(简单的类型)
1. 方式一:使用属性注入Student类型的对象
Student stu1 = new Student(); stu1.setStuNo(1001);.....
<!--利用property标签实现set设置属性的功能 -->
<!-- name对应实体类的属性名称,value对应你需要设置的属性值 -->
<property name="stuNo" value="1001"></property>
2. 方式二:使用构造方法注入Student类型的对象及属性值
Student stu1 = new Student(1001,"zhangsan"....);
<!-- index对应实体类的第几个属性,value对应你需要设置的属性值 -->
<constructor-arg index="0" value="1002"></constructor-arg>
3. 方式三:<!-- 使用构造方法中的参数名称 -->
<!-- name对应实体类的属性名称,value对应你需要设置的属性值 -->
<constructor-arg name="stuNo" value="1003"></constructor-arg>
4. 方式四:复合类型TODO
<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="person" class="com.neuedu.springtest.entity.Person">
bean>
<bean id="stu1" class="com.neuedu.springtest.entity.Student">
<property name="stuNo" value="1001">property>
<property name="stuName" value="zhangsan">property>
<property name="gender" value="男">property>
<property name="birthday" value="2001-09-08">property>
bean>
<bean id="stu2" class="com.neuedu.springtest.entity.Student">
<constructor-arg index="0" value="1002">constructor-arg>
<constructor-arg index="1" value="lisi">constructor-arg>
<constructor-arg index="2" value="女">constructor-arg>
<constructor-arg index="3" value="2001-09-09">constructor-arg>
bean>
<bean id="stu3" class="com.neuedu.springtest.entity.Student">
<constructor-arg name="stuNo" value="1003">constructor-arg>
<constructor-arg name="stuName" value="Jerry">constructor-arg>
<constructor-arg name="gender" value="女">constructor-arg>
<constructor-arg name="birthday" value="2001-02-03">constructor-arg>
bean>
beans>
package com.neuedu.springtest.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.neuedu.springtest.entity.Student;
/**
* @author 时万绘
*
*/
public class TestStudent {
public static void main(String[] args) {
// 加载Spring容器,解析指定的xml文件
// ApplicationContext是一个接口,ClassPathXmlApplicationContext是一个实现类
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-ioc.xml");
// 第一种方式
// 获取Student对象
Student zhangsan = (Student) context.getBean("stu1");
System.out.println("Test student zhangsan....");
// 打印结果为false说明成功调用无参构造方法创建Student实体类对象
System.out.println(zhangsan == null);
// 打印出注入的student属性内容
System.out.println(zhangsan);
// 第二种方式
Student lisi = (Student) context.getBean("stu2");
System.out.println(lisi);
// 第三种方式
Student Jerry = (Student) context.getBean("stu3");
System.out.println(Jerry);
}
}
四、使用Spring的DI(Depedency Injection)核心技术注入属性(复杂类型List、Map、Set、类对象)
4.1.1 新建Student实体类package com.neuedu.springtest.entity;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author 时万绘 定义学生实体类Student
*/
public class Student {
private Integer stuNo;
private String stuName;
private String gender;
private String birthday;
// 复杂类型List
private List<String> friends;
// 复杂类型Map
private Map<String, Integer> scores;
// 复杂类型Set
private Set<String> hobbies;
// 复杂类型类对象
private StuClass stuClass;
private List<Course> courses;
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
public Student(Integer stuNo, String stuName, String gender,
String birthday, List<String> friends, Map<String, Integer> scores,
Set<String> hobbies, StuClass stuClass) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
this.friends = friends;
this.scores = scores;
this.hobbies = hobbies;
this.stuClass = stuClass;
}
public Set<String> getHobbies() {
return hobbies;
}
public void setHobbies(Set<String> hobbies) {
this.hobbies = hobbies;
}
public Integer getStuNo() {
return stuNo;
}
public void setStuNo(Integer stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public Map<String, Integer> getScores() {
return scores;
}
public void setScores(Map<String, Integer> scores) {
this.scores = scores;
}
public StuClass getStuClass() {
return stuClass;
}
public void setStuClass(StuClass stuClass) {
this.stuClass = stuClass;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + ", gender="
+ gender + ", birthday=" + birthday + "]";
}
public Student(Integer stuNo, String stuName, String gender, String birthday,
List<String> friends, Map<String, Integer> scores, StuClass stuClass) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
this.friends = friends;
this.scores = scores;
this.stuClass = stuClass;
}
public Student() {
super();
}
public Student(Integer stuNo, String stuName, String gender, String birthday,
List<String> friends) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
this.friends = friends;
}
public Student(Integer stuNo, String stuName, String gender, String birthday) {
super();
this.stuNo = stuNo;
this.stuName = stuName;
this.gender = gender;
this.birthday = birthday;
}
}
package com.neuedu.springtest.entity;
/**
* @author 时万绘
*
*/
public class StuClass {
private int classNo;
private String className;
public int getClassNo() {
return classNo;
}
public void setClassNo(int classNo) {
this.classNo = classNo;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public StuClass(int classNo, String className) {
super();
this.classNo = classNo;
this.className = className;
}
public StuClass() {
super();
}
@Override
public String toString() {
return "StuClass [classNo=" + classNo + ", className=" + className
+ "]";
}
}
package com.neuedu.springtest.entity;
/**
* @author 时万绘
*
*/
public class Course {
private int courseNo;
private String courseName;
public int getCourseNo() {
return courseNo;
}
public void setCourseNo(int courseNo) {
this.courseNo = courseNo;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Course(int courseNo, String courseName) {
super();
this.courseNo = courseNo;
this.courseName = courseName;
}
public Course() {
super();
}
@Override
public String toString() {
return "Course [courseNo=" + courseNo + ", courseName=" + courseName
+ "]";
}
}
<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="person" class="com.neuedu.springtest.entity.Person">
bean>
<bean id="JavaClass" class="com.neuedu.springtest.entity.StuClass">
<property name="classNo" value="101">property>
<property name="className" value="Java1班">property>
bean>
<bean id="CPlusClass" class="com.neuedu.springtest.entity.StuClass">bean>
<bean id="HTML" class="com.neuedu.springtest.entity.Course">
<property name="courseNo" value="1001">property>
<property name="courseName" value="HTML">property>
bean>
<bean id="Oracle" class="com.neuedu.springtest.entity.Course">
<property name="courseNo" value="1002">property>
<property name="courseName" value="Oracle">property>
bean>
<bean id="JavaScript" class="com.neuedu.springtest.entity.Course">
<property name="courseNo" value="1003">property>
<property name="courseName" value="JavaScript">property>
bean>
<bean id="stu1" class="com.neuedu.springtest.entity.Student">
<property name="stuNo" value="1001">property>
<property name="stuName" value="zhangsan">property>
<property name="gender" value="男">property>
<property name="birthday" value="2001-09-08">property>
<property name="hobbies">
<set>
<value>旅行value>
<value>唱歌value>
<value>跳舞value>
<value>阅读value>
set>
property>
<property name="friends">
<list>
<value>小明value>
<value>小花value>
<value>小时value>
list>
property>
<property name="scores">
<map>
<entry key="java" value="85">entry>
<entry key="html" value="95">entry>
<entry key="javascript" value="80">entry>
<entry key="jQuery" value="75">entry>
map>
property>
<property name="stuClass" ref="JavaClass">property>
<property name="courses">
<list>
<ref bean="HTML"/>
<ref bean="Oracle"/>
list>
property>
bean>
<bean id="stu2" class="com.neuedu.springtest.entity.Student">
<constructor-arg index="0" value="1002">constructor-arg>
<constructor-arg index="1" value="lisi">constructor-arg>
<constructor-arg index="2" value="女">constructor-arg>
<constructor-arg index="3" value="2001-09-09">constructor-arg>
bean>
<bean id="stu3" class="com.neuedu.springtest.entity.Student">
<constructor-arg name="stuNo" value="1003">constructor-arg>
<constructor-arg name="stuName" value="Jerry">constructor-arg>
<constructor-arg name="gender" value="女">constructor-arg>
<constructor-arg name="birthday" value="2001-02-03">constructor-arg>
bean>
beans>
package com.neuedu.springtest.test;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.neuedu.springtest.entity.Course;
import com.neuedu.springtest.entity.StuClass;
import com.neuedu.springtest.entity.Student;
/**
* @author 时万绘
*
*/
public class TestStudentWithMulti {
public static void main(String[] args) {
// 加载Spring容器,解析指定的xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring-ioc.xml");
// 获取Student对象
Student zhangsan = (Student) context.getBean("stu1");
System.out.println(zhangsan);
// 获取stu1对象的set类型的属性值
Set<String> hobbies = zhangsan.getHobbies();
System.out.println(hobbies);
// 获取学生的List类型属性值
List<String> friends = zhangsan.getFriends();
System.out.println(friends);
// 获取学生的Map类型的属性值
Map<String,Integer> scores = zhangsan.getScores();
System.out.println(scores);
// 获取学生的班级信息(自动以其他类型的对象)
StuClass stuClass = zhangsan.getStuClass();
System.out.println(stuClass);
// 获取学生的选课信息属性
List<Course> courses = zhangsan.getCourses();
courses.forEach(System.out :: println);
}
}
四、Ioc容器与装配Bean
4.1、Ioc容器和依赖注入的基础知识点
4.1.1、Ioc容器
1. Ioc(Inverse of Control)控制反转:DL + DI(依赖注入),是Spring框架的核心,基于工厂模式(构建bean的工厂),对象的创建由程序员的New被反转给spring容器进行处理
2. DI(依赖注入)管理构成应用的组件,创建相互协作的组件之间的联系;
3. Ioc容器内部协作:Spring容器、Bean配置信息、Bean实现类及应用程序四者的相互关系,见下图:4-1
4. Bean配置信息的几种方式:XML<bean>、Groovy beans、Java类@Configuration、注解@Autowrite
注: <bean id = "xxx" class="xxx">id相当于key(起一个别名),不可重复,class相当于value可以重复(类全限定名称),scope="单例模式/原型模式"
5. Spring通过配置文件描述Bean及Bean之间的依关系,利用Java的反射机制实例化Bean并建立Bean之间的依赖关系
6. ApplicationContext接口与BeanFactory的区别?【考点】
答:
--BeanFactory:
· Bean工厂是Spring框架最核心的接口,提供Ioc的配置机制,使管理不同类型的Java对象成为可能
· 采用延迟加载的Bean,直到第一次使用getBean()方法获取Bean实例时,才会创建Bean
--ApplicationContext应用上下文:
· 建立在BeanFactory基础之上,提供更多面向应用的功能,如:国际化支持、框架时间体系、更易于创建实际应用;
· ApplicationContext类体系结构,主要实现类是两个配置文件:ClassPathXMLApplicationContext(从类路径加载配置文件)、FilesSystemXmlApplicationContext(从文件系统中加载配置文件)
·ApplicationContext在自身被实例化时一次完成所有的Bean的创建,大多数时候使用ApplicationContext
-- 二者区别:
· 在服务启动时ApplicationContext就会校验XML文件的正确性,不会产生运行时bean装配错误
· BeanFactory在服务启动时,不会校验XML文件的正确性,获取Bean时,如果装配错误马上就会产生异常
7. 依赖注入的实现方式?
答:共有三种实现方式。构造函数注入(参数类型、参数个数、参数的名称)、属性注入、接口注入
4.1.2、依赖注入
4.2、Bean的作用域
4.2.1、Spring中支持的5种作用域
4.3、基于注解的配置
4.4、基于注解的配置的代码演示
4.4.1、新建一个实体类Teacher.java
package com.neuedu.springtest.entity;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("tea")
// 是哪一层就@哪一个控制层
//@Controller服务层即@Service
@Scope("prototype")
public class Teacher {
private int teaNo;
private String teaName;
private String courseName;
public int getTeaNo() {
return teaNo;
}
public void setTeaNo(int teaNo) {
this.teaNo = teaNo;
}
public String getTeaName() {
return teaName;
}
public void setTeaName(String teaName) {
this.teaName = teaName;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Teacher(int teaNo, String teaName, String courseName) {
super();
this.teaNo = teaNo;
this.teaName = teaName;
this.courseName = courseName;
}
public Teacher() {
super();
}
@Override
public String toString() {
return "Teacher [teaNo=" + teaNo + ", teaName=" + teaName
+ ", courseName=" + courseName + "]";
}
}
4.4.2、新建一个配置文件spring-ioc-anno.xml
<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:annotation-config>
<context:component-scan base-package="com.neuedu.springtest">
context:component-scan>
beans>
4.4.3、新建一个测试类TestAnno.java
package com.neuedu.springtest.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.neuedu.springtest.entity.Teacher;
/**
* @author 时万绘
* */
public class TestAnno {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-ioc-anno.xml");
Teacher tea = (Teacher) context.getBean("tea");
System.out.println(tea == null);
Teacher tea1 = (Teacher) context.getBean("tea");
System.out.println(tea == tea1);
}
}
4.4.4、测试类TestAnno控制台效果
@Scope(prototype)-- 设置原型模式
4.3、使用Spring注解整合–含业务层和dao层代码[没有涉及数据库]
@Service(“teaBiz”)或者@Service注解加在业务层的实现类上
4.3.1、新建Dao层的ITeacherDao.java
package com.neuedu.springtest.dao;
import com.neuedu.springtest.entity.Teacher;
/**
* @author 时万绘
* 数据库层接口类
*/
public interface ITeacherDao {
// 根据教师编号查询教师信息
public Teacher getTeacherByTeaNo(int teaNo);
}
4.3.2、新建Dao层的接口实现类TeacherImpl.java
package com.neuedu.springtest.dao.impl;
import org.springframework.stereotype.Repository;
import com.neuedu.springtest.dao.ITeacherDao;
import com.neuedu.springtest.entity.Teacher;
/**
* @author 时万绘
* 数据库层接口的实现类
*/
@Repository
// @Repository用于访问数据库
public class TeacherImpl implements ITeacherDao {
@Override
public Teacher getTeacherByTeaNo(int teaNo) {
System.out.println("编号为" + teaNo + "的教师信息为....");
return null;
}
}
4.3.3、新建业务层接口ITeacherBiz.java
package com.neuedu.springtest.biz;
import com.neuedu.springtest.entity.Teacher;
/**
* @author 时万绘
* 教师的业务层接口
*/
public interface ITeacherBiz {
// 根据教师编号查询教师信息
public Teacher getTeacherByTeaNo(int teaNo);
}
4.3.4、新建测试类TestAnno.java
package com.neuedu.springtest.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.neuedu.springtest.biz.ITeacherBiz;
import com.neuedu.springtest.entity.Teacher;
/**
* @author 时万绘
* 测试类
*/
public class TestAnno {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"spring-ioc-anno.xml");
Teacher tea = (Teacher) context.getBean("tea");
System.out.println(tea == null);
Teacher tea1 = (Teacher) context.getBean("tea");
System.out.println(tea == tea1);
// 使用注解实现Service-->Dao的访问
ITeacherBiz teaBiz = (ITeacherBiz) context.getBean("teaBiz");
System.out.println(teaBiz == null);
// 调用业务层的方法
teaBiz.getTeacherByTeaNo(1001);
}
}
4.3.5、查看控制台效果图
4.4、使用Spring-test进行测试–Spring自带的JUnit
4.4.1、新建测试类testTeacherBiz.java
4.4.2、pom.xml文件中新增JUnit依赖和Spring-test依赖
https://mvnrepository.com/artifact/junit/junit/4.12
https://mvnrepository.com/artifact/org.springframework/spring-test/5.1.5.RELEASE
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>5.1.5.RELEASEversion>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
4.4.3、新建测试类testTeacherBiz.java
package com.neuedu.springtest.biz.impl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.biz.ITeacherBiz;
/**
* @author 时万绘
* 1.pom文件中增加JUit和Spring-test(来源于Maven仓库)
* 2.JUnit方法的好处避免重复编写main方法以及ApplicationContext
*/
// RunWith是固定代码
@RunWith(SpringJUnit4ClassRunner.class)
// 字符串数组,可以写多个,locations属性的值为自己的配置文件
@ContextConfiguration(locations={
"classpath:spring-ioc-anno.xml"})
public class testTeacherBiz{
@Autowired
// 通过自动装配获取TeacherBiz的实现类对象
private ITeacherBiz teaBiz;
/**
* 测试方法
*/
@Test
public void testGetTeacherByNo(){
System.out.println(teaBiz == null);
// 调用方法
teaBiz.getTeacherByTeaNo(1001);
}
}
4.4.4、控制台运行效果
4.5、基于Java的类配置–实例【不涉及数据库实际数据】
通过@Configuration的java类启动Spring容器
* 标注了@Configuration和@Component的类一样时一个Bean,可以被<context:component-scan>扫描到
* 通过@Configuration配置类引用xml配置信息
在@Configuration配置类中可以通过@ImportResource或@ContextConfiguration引入配置xml文件
工程目录如下图:
4.5.1、新建业务层接口IPersonBiz.java
package com.neuedu.springtest.biz;
/**
* @author 时万绘
* 定义业务层接口类
*/
public interface IPersonBiz {
// 根据身份证号码删除个人信息
public int deletePerson(String cardNo);
}
4.5.2、新建业务层接口实现类PersonBizImpl.java
package com.neuedu.springtest.biz.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.neuedu.springtest.biz.IPersonBiz;
import com.neuedu.springtest.dao.IPersonDao;
/**
* @author 时万绘
* 没有使用注解,采用java配置类来获取的
*/
public class PersonBizImpl implements IPersonBiz{
// 实例化PersonDao接口的对象,如果没有注解就是一个空对象
@Autowired
// 自动装配,指定IPersonDao类的对象来源,Spring容器来注入bean
private IPersonDao personDao;
@Override
public int deletePerson(String cardNo) {
return personDao.deletePerson(cardNo);
}
}
4.5.3、新建持久层接口IPersonDao.java
package com.neuedu.springtest.dao;
/**
* @author 时万绘
* 定义数据库操作的接口
*/
public interface IPersonDao {
public int deletePerson(String cardNo);
}
4.5.4、新建持久层接口实现类PersonDaoImpl.java
package com.neuedu.springtest.dao.impl;
import com.neuedu.springtest.dao.IPersonDao;
/**
* @author 时万绘
* 数据库接口的实现类
*/
public class PersonDaoImpl implements IPersonDao {
// 根据身份证号删除个人信息
public int deletePerson(String cardNo){
System.out.println("准备删除身份证编号是:" + cardNo + "的信息..." );
return 0;
}
}
4.5.5、新建配置类PersonConfig.java
package com.neuedu.springtest.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.neuedu.springtest.biz.IPersonBiz;
import com.neuedu.springtest.biz.impl.PersonBizImpl;
import com.neuedu.springtest.dao.IPersonDao;
import com.neuedu.springtest.dao.impl.PersonDaoImpl;
/**
* @author 时万绘
* 配置类PersonConfig
*/
@Configuration
public class PersonConfig {
// 构建Bean对象
@Bean
// Bean的id属性默认是personDao方法名
public IPersonDao personDao(){
return new PersonDaoImpl();
}
@Bean(name="perBiz")
public IPersonBiz getPersonBiz(){
return new PersonBizImpl();
}
}
4.5.6、新建测试类TestJavaConfig.java
package com.neuedu.springtest.biz.impl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.biz.IPersonBiz;
import com.neuedu.springtest.config.PersonConfig;
/**
1. @author 时万绘
2. 配置类的测试
*/
@RunWith(SpringJUnit4ClassRunner.class)
// 加载java配置类
@ContextConfiguration(classes=PersonConfig.class)
public class TestJavaConfig {
@Autowired
private IPersonBiz perBiz;
@Test
public void testDeletePerson(){
System.out.println(perBiz == null);
// 调用方法
perBiz.deletePerson("320921199009090909");
}
}
4.5.7、控制台效果
4.6、Bean不同配置方式的比较
3. 基于xml方式配置:
· Bean实现类来源于第三方类库,如DataSource、SessionFactory等资源的Bean(初始化,sessionFactory就是mybaties)
· 命名空间的配置,如AOP、context等,智能采用基于XML的配置
4. 基于注解方式的配置(自己编写的代码,直接在Java类中使用基于注解的配置)
5. 基于Java类的配置(应用场景:实例化Bean代码比较复杂时)
6. 建议整个项目采用:"基于XML + 基于注解 "的配置方式
五、AOP
5.1、AOP的基础知识
注:AOP的作用就是开关门---程序员只需要放大象即可
7. AOP(Aspect Oritented Programming)面向切面编程;利用AOP对业务逻辑的各部分进行隔离,使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性
8. AOP的应用场景:性能检测、访问控制、事务控制、日志记录等【登录验证(之前执行)|打卡记录(之后执行)|日志记录】
9. AOP的作用:横切关注点:操作日志、安全检测、事务处理,横切一刀在切点的位置加入需要的代码和方法,如图5-1所示
10. 以验证用户登录为例:
AOP术语:
· 切面(Aspect)--切是由切点和通知组成的,什么时候去做(定义业务逻辑)
· 连接点(joinpoint)连接点是在应用执行过程中能够插入切面的一个点,Spring仅支持方法的连接点
· 切点(Pointcut)切点定义了在何处应用切面,切点相当于查询条件,个切点可以匹配多个连接点
· 通知(Advice)(业务逻对应的方法如何执行)【也称:增强】
--权限验证(在方法之前Before)
--日志(在方法之后After)
--环绕通知(Around advice)
--异常通知(After-throwing)
--返回通知(After-returning)
· 目标对象(Target)通知逻辑的织入目标类,目标类只需要实那些非横切逻辑的程序逻辑
· 引入(Introduction)引介是一种特殊的通知,为类添加一些属性和方法
· 代理(Proxy)一个类被AOP织入通知后,就产生一个结果类,融合了原类和通知逻辑的代理类
· 织入(Weaving)AOP像一台织布机,将目标类、通知或引介编织到一起
AOP的三种织入方式:
-- 编译器织入:切面在目标类的编译时被织入,需要特殊的编译器
-- 类装载期织入:切面在目标类加载到JVM时被织入,需要特殊的编译器
-- 动态代理织入:切面在应用运行的某个时刻被织入,AOP容器会为目标对象动态创建一个代理对象
11. Spring采用动态代理织入,AspectJ采用编译期织入和类装载期织入
5.1.1、AOP的开源框架的支持
12. AOP框架的设计目标:把横切的问题模块化(如:性能检测、事务处理)
13. 目前常用的AOP框架如下:
· Aspect J(Eclipse旗下的项目,是语言级的AOP实现)
· AspectWerkz(基于java的简单、动态、轻量级的AOP框架)
· Spring AOP (使用java实现)
5.1.2、Spring对AOP的支持
1. Spring提供了四种类型的AOP支持:
· 基于经典的SpringAOP
· 纯POJO切面
· @AspectJ注解驱动的切面
· 注入式AspectJ切面
2.前三种都是SpringAOP实现的变体,Spring AOP构建的动态代理基础之上
5.1.3、Spring对AOP的代理机制【重点】
1. 基于JDK的动态代理,针对接口的代理
· Spring的AOP的默认实现就是采用jdk的动态代理机制实现的
· 自java1.3之后,java提供了动态代理技术,允许开发者在运行期创建接口的代理实例
2. 基于CGLib的动态代理,针对的类的代理
· JDK只能为接口创建代理实例,对于那些没有通过接口定义业务方法的类,可以通过CGLib创建代理实例
· CGLib采用底层字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有的父类方法的调用,这时可以顺势织入横切逻辑
3. JDK动态代理主要涉及两个类:
·java.lang.reflect.Proxy
·java.lang.reflect.InvocationHandler
InvocationHandler是一个接口,可以实现该接口定义的横切逻辑,通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起
·Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象
5.2、AOP中的两种代理方式
未采用AOP代理模式时的代码流程演示
package com.neuedu.springtest.biz;
/**
* @author 时万绘
* 用户的业务层接口
*
*/
public interface IUserBiz {
// 新增用户(用户名密码)
public void insertUser(String username,String password );
// 根据用户编号删除用户
public void deleteUser(int userNo);
}
package com.neuedu.springtest.biz.impl;
import com.neuedu.springtest.biz.IUserBiz;
/**
* @author 时万绘
* 用户业务层实现类
*/
public class UserBizImpl implements IUserBiz {
@Override
public void insertUser(String username, String password) {
// 没有使用代理时的权限验证操作
// AuthValidate auth = new AuthValidate();
// auth.validate();
System.out.println("准备添加username = " + username
+ ",password" + password);
}
@Override
public void deleteUser(int userNo) {
System.out.println("准备删除" + userNo + "的用户");
}
}
package com.neuedu.springtest.test;
import org.junit.Test;
import com.neuedu.springtest.biz.IUserBiz;
import com.neuedu.springtest.biz.impl.UserBizImpl;
import com.neuedu.springtest.proxy.JDKProxySample;
/**
* @author 时万绘
* JDK代理的测试
*/
public class TestJDKProxy {
@Test
public void testUserBiz(){
IUserBiz userBiz = new UserBizImpl();
// 调用方法
userBiz.insertUser("zhangsan","123");
userBiz.deleteUser(101);
}
}
5.2.1、AOP中的两种代理方式—JDKProxy方式(针对接口的代理)
应用场景:在新增用户和删除用户前需要进行权限认证和日志记录
5.2.1.1、新建一个业务层接口IUserBiz.java
package com.neuedu.springtest.biz;
/**
* @author 时万绘
* 用户的业务层接口
*/
public interface IUserBiz {
// 新增用户(用户名密码)
public void insertUser(String username,String password );
// 根据用户编号删除用户
public void deleteUser(int userNo);
}
5.4.1.2、新建一个业务层接口实现类UserBizImpl.java
package com.neuedu.springtest.biz.impl;
import com.neuedu.springtest.biz.IUserBiz;
/**
* @author 时万绘
* 用户业务层实现类
*/
public class UserBizImpl implements IUserBiz {
@Override
public void insertUser(String username, String password) {
// 没有使用代理时的权限验证操作
// AuthValidate auth = new AuthValidate();
// auth.validate();
System.out.println("准备添加username = " + username
+ ",password" + password);
}
@Override
public void deleteUser(int userNo) {
System.out.println("准备删除" + userNo + "的用户");
}
}
5.2.1.3、新建一个测试类TestJDKProxy.java
package com.neuedu.springtest.test;
import org.junit.Test;
import com.neuedu.springtest.biz.IStudentBiz;
import com.neuedu.springtest.biz.IUserBiz;
import com.neuedu.springtest.biz.impl.StudentBizImpl;
import com.neuedu.springtest.biz.impl.UserBizImpl;
import com.neuedu.springtest.proxy.JDKProxySample;
/**
* @author 时万绘
* JDK代理的测试
*/
public class TestJDKProxy {
@Test
public void testUserBiz(){
IUserBiz userBiz = new UserBizImpl();
// 调用方法
userBiz.insertUser("zhangsan","123");
userBiz.deleteUser(101);
// 创建JDK动态代理类
JDKProxySample proxy = new JDKProxySample();
// 使用JDK动态代理对象调用newProxy方法
IUserBiz userBizProxy = (IUserBiz) proxy.newProxy(userBiz);
// IUserBiz userBizProxy = (IUserBiz) proxy.newProxy(new UserBizImpl());
// 调用方法
userBizProxy.insertUser("lisi", "1234");
userBizProxy.deleteUser(102);
// JDK动态代理IStudentBiz对象
IStudentBiz stuBiz = (IStudentBiz) proxy.newProxy(new StudentBizImpl());
// 调用方法
stuBiz.updateStudent("Jack", "男", 10002);
}
}
5.2.1.4、新建一个AOP动态代理类AuthAspect.java
package com.neuedu.springtest.aspect;
/**
* @author 时万绘
* 切面(需要织入的代码)
* 避免代码的耦合和冗余
*/
public class AuthAspect {
// 验证用户权限的方法
public void validateUser(){
System.out.println("在执行操作之前,需要验证用户权限。。");
}
// 日志的方法
public void logOperator(){
System.out.println("在执行操作之后,需要记录日志信息。。。");
}
}
5.2.1.5、新建一个AOP动态代理实现类JDKProxySample.java
package com.neuedu.springtest.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.neuedu.springtest.aspect.AuthAspect;
/**
* @author 时万绘
*
*/
public class JDKProxySample implements InvocationHandler {
// 定义对象,要传入的目标对象,即需要代理的对象
private Object targetObject;
/**
* @param obj
* @return
* 将目标对象传递进来,创建代理类并返回
*/
public Object newProxy(Object obj){
this.targetObject = obj;
// getClassLoader利用反射机制
// 利用 Proxy.newProxyInstance实例化一个对象
// JDK代理只能针对接口,this指的是当前的类
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader()
, targetObject.getClass().getInterfaces()
, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
// 需要经过这个切面
AuthAspect aspect = new AuthAspect();
// 调用方法前做权限认证
// validateUser权限验证
aspect.validateUser();
result = method.invoke(this.targetObject, args);
// 获取方法名称,根据方法名称进行判断,是否需要权限验证与日志记录
// method.getName();
// 调用方法后做日志处理
aspect.logOperator();
return result;
}
}
运行效果图:
5.2.1.6、新建一个学生接口类IStudentBiz.java
package com.neuedu.springtest.biz;
/**
1. @author 时万绘
2. */
public interface IStudentBiz {
// 更新学生信息
public void updateStudent(String stuName,String gender,int stuNo);
}
5.2.1.7、新建一个学生接口的实现类StudentBizImpl.java
package com.neuedu.springtest.biz.impl;
import com.neuedu.springtest.biz.IStudentBiz;
/**
3. @author 时万绘
4. 更新业务操作利用JDKProxy代理实现
5. 更新前验证权限,更新后记录日志信息
*/
public class StudentBizImpl implements IStudentBiz {
@Override
public void updateStudent(String stuName, String gender, int stuNo) {
System.out.println("准备更新学生信息,信息如下:stuName=" + stuName +
",stuNo=" + stuNo + ",gender=" + gender );
}
}
5.2.1.8、控制台测试运行效果
更新学生信息时业务逻辑层没有验证的代码,但是运行测试时,依然调用了AOP的JDK动态代理的方法实现了操作前与操作后的权限认证和日志记录
5.2.2、AOP中的两种代理方式—CGlib方式【针对类的代理】
1. List item
2. xx
3. xxx
4.
5.2.2.1、新建一个RoleBizImpl.java类
package com.neuedu.springtest.biz.impl;
/**
* @author 时万绘
* 创建没有借口的业务层方法类
*
*/
public class RoleBizImpl {
public int addRole(int roleId,String roleName){
System.out.println("正在添加角色信息为:" + roleId + "," + roleName + "的角色用户");
return 0;
}
public int deleteRole(int roleId){
System.out.println("正在删除角色id为:" + roleId + "的角色信息");
return 0;
}
}
5.2.2.2、检测不是接口的类能否使用JDK动态代理–TestJDKProxy.java类
package com.neuedu.springtest.test;
import org.junit.Test;
import com.neuedu.springtest.biz.IStudentBiz;
import com.neuedu.springtest.biz.IUserBiz;
import com.neuedu.springtest.biz.impl.RoleBizImpl;
import com.neuedu.springtest.biz.impl.StudentBizImpl;
import com.neuedu.springtest.biz.impl.UserBizImpl;
import com.neuedu.springtest.proxy.JDKProxySample;
/**
* @author 时万绘
* JDK代理的测试
*/
public class TestJDKProxy {
@Test
public void testUserBiz(){
IUserBiz userBiz = new UserBizImpl();
// 调用方法
userBiz.insertUser("zhangsan","123");
userBiz.deleteUser(101);
// 创建JDK动态代理类
JDKProxySample proxy = new JDKProxySample();
// 使用JDK动态代理对象调用newProxy方法
IUserBiz userBizProxy = (IUserBiz) proxy.newProxy(userBiz);
// IUserBiz userBizProxy = (IUserBiz) proxy.newProxy(new UserBizImpl());;
// 调用方法
userBizProxy.insertUser("lisi", "1234");
userBizProxy.deleteUser(102);
// JDK动态代理IStudentBiz对象
IStudentBiz stuBiz = (IStudentBiz) proxy.newProxy(new StudentBizImpl());
// 调用方法
stuBiz.updateStudent("Jack", "男", 10002);
// // 使用JDK动态代理没有接口的类(RoleBizImpl不是接口的实现类,以下代码报错)
// RoleBizImpl roleBiz = (RoleBizImpl) proxy.newProxy(new RoleBizImpl());
// // 调用方法
// roleBiz.addRole(1, "admin");
// roleBiz.deleteRole(1);
}
}
5.2.2.3、新建一个CGLib动态代理类CGLibProxySample.java类
package com.neuedu.springtest.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import com.neuedu.springtest.aspect.AuthAspect;
/**
* @author 时万绘
* CGLibProxySample动态代理
*/
public class CGLibProxySample implements MethodInterceptor {
// 定义要代理的对象
private Object targetObject;
// 获取代理对象
public Object getCGLibProxy(Object targetObject){
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(this.targetObject.getClass());
enhancer.setCallback(this);
Object obj = enhancer.create();
return obj;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("CGLib proxy intercept method....");
// 创建切面对象
AuthAspect aspect = new AuthAspect();
// 方法执行前调用权限验证
aspect.validateUser();
Object result = method.invoke(targetObject, args);
// 方法调用后执行日志记录
aspect.logOperator();
return result;
}
}
5.2.2.4、新建一个动态打印信息的类AuthAspect.java类
package com.neuedu.springtest.aspect;
/**
* @author 时万绘
* 切面(需要织入的代码)
* 避免代码的耦合和冗余
*/
public class AuthAspect {
// 验证用户权限的方法
public void validateUser(){
System.out.println("在执行操作之前,需要验证用户权限。。");
}
// 日志的方法
public void logOperator(){
System.out.println("在执行操作之后,需要记录日志信息。。。");
}
}
5.2.2.5、新建一个测试类TestCGLibProxy.java类
package com.neuedu.springtest.test;
import org.junit.Test;
import com.neuedu.springtest.biz.impl.RoleBizImpl;
import com.neuedu.springtest.proxy.CGLibProxySample;
/**
* @author 时万绘
* CGLibProxy测试类
*/
public class TestCGLibProxy {
@Test
public void testRoleBizNotInterfaceByCGLibProxy(){
CGLibProxySample proxy = new CGLibProxySample();
RoleBizImpl roleBiz = (RoleBizImpl) proxy.getCGLibProxy(new RoleBizImpl());
// 调用roleBiz中的方法
roleBiz.addRole(1, "admin");
roleBiz.deleteRole(1);
}
}
5.2.3、CGlib方式【针对类的代理】–AOPXML文件的配置
5.2.3.1 新建一个测试接口IEmployeeBiz.java
package com.neuedu.springtest.biz;
/**
* @author 时万绘
* 新建接口类
*/
public interface IEmployeeBiz {
public int getEmployee(int empNo);
public int getAllEmployee();
public int addEmployee(int empNo,String empName);
public int deleteEmployee(int empNo);
public int updateEmployee(int empNo,String empName,String gender);
}
5.2.3.2 新建一个测试接口实现类EmployeeBizImpl类.java
package com.neuedu.springtest.biz.impl;
import com.neuedu.springtest.biz.IEmployeeBiz;
/**
* @author 时万绘
* 实现业务:
* ·在方法中做查询操作时实现日志记录
* ·做增删改时要进行权限认证
*/
public class EmployeeBizImpl implements IEmployeeBiz {
@Override
public int getEmployee(int empNo) {
System.out.println("编号为:empNo=" + empNo + "的信息如下...");
return 0;
}
@Override
public int addEmployee(int empNo, String empName) {
System.out.println("新增员工信息:empNo = " + empNo + ",员工姓名:" + empName);
return 0;
}
@Override
public int deleteEmployee(int empNo) {
System.out.println("根据员工编号删除empNo = " + empNo + "的员工信息..." );
return 0;
}
@Override
public int updateEmployee(int empNo, String empName, String gender) {
System.out.println("更新员工信息:empNo = " + empNo + ",empName = " + empName + ",gender = " + gender);
return 0;
}
@Override
public int getAllEmployee() {
System.out.println("查询所有员工的信息");
return 0;
}
}
5.2.3.3 新建一个信息打印类AuthAspect.java
package com.neuedu.springtest.aspect;
/**
* @author 时万绘
* 切面(需要织入的代码)
* 避免代码的耦合和冗余
*/
public class AuthAspect {
// 验证用户权限的方法
public void validateUser(){
System.out.println("在执行操作之前,需要验证用户权限。。");
}
// 日志的方法
public void logOperator(){
System.out.println("在执行操作之后,需要记录日志信息。。。");
}
}
5.2.3.4 新建一个配置文件spring-aop.xml
<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"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="empBiz" class="com.neuedu.springtest.biz.impl.EmployeeBizImpl">bean>
<bean id="authAspect" class="com.neuedu.springtest.aspect.AuthAspect">bean>
<aop:config>
<aop:aspect ref="authAspect">
<aop:pointcut
expression="execution(* com.neuedu.springtest.biz.impl.EmployeeBizImpl.get*(..))"
id="logPointCut" />
<aop:pointcut
expression="execution(* com.neuedu.springtest.biz.impl.EmployeeBizImpl.*Employee(..))"
id="authPointCut" />
<aop:before method="validateUser" pointcut-ref="authPointCut" />
<aop:after method="logOperator" pointcut-ref="logPointCut" />
aop:aspect>
aop:config>
beans>
5.2.3.5 新建一个测试类TestSpringAOPXML.java
package com.neuedu.springtest.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.biz.IEmployeeBiz;
/**
* @author 时万绘
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:spring-aop.xml"})
public class TestSpringAOPXML {
@Autowired
private IEmployeeBiz empBiz;
@Test
public void testEmployeeBiz(){
System.out.println(empBiz == null);
// 调用方法
empBiz.addEmployee(1010, "zhangsan");
System.out.println("---------查询操作--------");
// 查新操作之后进行日志记录
empBiz.getAllEmployee();
System.out.println("---------修改操作--------");
empBiz.updateEmployee(1010, "Jack", "男");
}
}
5.2.3.6 新添加一个依赖pom.xml
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.2version>
dependency>
5.2.3.7 查看控制台效果
5.2.4、CGlib方式【针对类的代理】-- 注解方式实现Aspect
5.2.4.1、新建接口ISchoolBiz.java
package com.neuedu.springtest.biz;
/**
* @author 时万绘
* 定义基于注解的测试接口
*/
public interface ISchoolBiz {
public int insertStudent(int stuNo,String stuName,String gender);
public int updateStudnet(int stuNo,String stuName,String gender);
public int deleteStudent(int stuNo);
public void getStudent(int stuNo);
}
5.2.4.2、新建接口的实现类SchoolBizImpl.java
package com.neuedu.springtest.biz.impl;
import org.springframework.stereotype.Service;
import com.neuedu.springtest.biz.ISchoolBiz;
/**
* @author 时万绘
* 创建基于注解的接口的测试实现类
*/
@Service
public class SchoolBizImpl implements ISchoolBiz {
@Override
public int insertStudent(int stuNo, String stuName, String gender) {
System.out.println("准备添加学号是:" + stuNo + ",姓名是:" + stuName + ",性别是:" + gender + "的学生信息");
return 0;
}
@Override
public int updateStudnet(int stuNo, String stuName, String gender) {
System.out.println("准备修改学号是:" + stuNo + ",姓名是:" + stuName + ",性别是:" + gender + "的学生信息");
return 0;
}
@Override
public int deleteStudent(int stuNo) {
System.out.println("准备删除学号是:" + stuNo + "的学生信息");
return 0;
}
@Override
public void getStudent(int stuNo) {
System.out.println("学生的学号为:" + stuNo + "的个人信息如下..." );
}
}
5.2.4.3、新建切片类SchoolAspect.java
package com.neuedu.springtest.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* @author 时万绘
* 采用的注解的方式进行日志记录和权限认证
*/
@Component
// 基于注解的所有加一个Component
@Aspect
// 将该类标识为一个切面
public class SchoolAspect {
@Before("execution(* com.neuedu.springtest.biz.impl.SchoolBizImpl.*(..))")
// 验证用户权限的方法
public void validateUser(){
System.out.println("----采用注解的方式----");
System.out.println("在执行操作之前,需要验证用户权限。。");
}
@After("execution(* com.neuedu.springtest.biz.impl.SchoolBizImpl.get*(..))")
// 日志的方法
public void logOperator(){
System.out.println("----采用注解的方式----");
System.out.println("在执行操作之后,需要记录日志信息。。。");
}
}
5.2.4.4、新建配置文件spring-aop-anno.xml
<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"
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/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config>context:annotation-config>
<context:component-scan base-package="com.neuedu.springtest.biz.impl">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>
5.2.4.5、新建配测试类TestSpringAOPAnno.java
package com.neuedu.springtest.biz.impl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.biz.ISchoolBiz;
/**
* @author 时万绘
* 注解的测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:spring-aop-anno.xml"})
public class TestSpringAOPAnno {
@Autowired
private ISchoolBiz schoolBiz;
@Test
public void testSchoolBiz(){
System.out.println(schoolBiz == null);
// 调用方法
schoolBiz.deleteStudent(1001);
schoolBiz.getStudent(1001);
}
}
六、Spring对DAO的支持
https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2/2.5.0
https://mvnrepository.com/artifact/org.springframework/spring-jdbc/5.1.5.RELEASE
https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.466.1、Spring配置数据源
1. 数据源
2. 配置DBCP数据源
6.1.1、添加依赖Pom.xml
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-dbcp2artifactId>
<version>2.5.0version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.5.RELEASEversion>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
6.1.2、新建一个实体类Department.java
package com.neuedu.springtest.entity;
/**
* @author 时万绘
* 新建部门实体类
*/
public class Department {
private int deptNo;
private String deptName;
private String location;
public int getDeptNo() {
return deptNo;
}
public void setDeptNo(int deptNo) {
this.deptNo = deptNo;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Department() {
super();
}
public Department(int deptNo, String deptName, String location) {
super();
this.deptNo = deptNo;
this.deptName = deptName;
this.location = location;
}
@Override
public String toString() {
return "Department [deptNo=" + deptNo + ", deptName=" + deptName
+ ", location=" + location + "]";
}
}
6.1.3、新建一个接口IDepartmentDao.java
package com.neuedu.springtest.dao;
import java.util.List;
import com.neuedu.springtest.entity.Department;
/**
* @author 时万绘
* string对DAO的支持
* 部门接口类
* */
public interface IDepartmentDao {
public Department getDepartmentByDeptNo(int deptNo);
public List<Department> getAllDepartments();
public int insertDepartment(Department dept);
public int deleteDepartment(int deptNo);
public int updateDepartment(Department dept);
}
6.1.4、新建一个接口的实现类DepartmentDaoImpl.java
package com.neuedu.springtest.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.neuedu.springtest.dao.IDepartmentDao;
import com.neuedu.springtest.entity.Department;
/**
* @author 时万绘
* Spring对DAO的支持
* 部门接口实现类
*/
@Repository
// @Repository连接数据库
public class DepartmentDaoImpl implements IDepartmentDao {
@Autowired
private JdbcTemplate jt;
@Override
public Department getDepartmentByDeptNo(int deptNo) {
// 指定要执行的SQL语句
String sql = "select * from dept where deptNo = ?";
// 设置参数
Object[] params = {
deptNo};
// 返回结果集
return jt.queryForObject(sql, params,new RowMapper<Department>(){
@Override
public Department mapRow(ResultSet rs, int rowNum)
throws SQLException {
Department dept = new Department();
dept.setDeptNo(100001);
dept.setDeptName("zhangsan");
dept.setLocation("Nanjing");
return null;
}
});
}
@Override
public List<Department> getAllDepartments() {
return null;
}
@Override
public int insertDepartment(Department dept) {
return 0;
}
@Override
public int deleteDepartment(int deptNo) {
return 0;
}
@Override
public int updateDepartment(Department dept) {
return 0;
}
}
6.1.5、新建一个连接数据源的配置文件spring-jdbc.xml
https://docs.spring.io/spring/docs/5.1.7.RELEASE/spring-framework-reference/core.html#spring-core
<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: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">
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost/mysqldb"
p:username="root"
p:password="root123"/>
<bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource">bean>
<context:annotation-config>context:annotation-config>
<context:component-scan base-package="com.neuedu.springtest">context:component-scan>
beans>
6.1.6、新建一个测试类TestSpringDao.java
package com.neuedu.springtest.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.dao.IDepartmentDao;
import com.neuedu.springtest.entity.Department;
/**
* @author 时万绘
* Spring对于DAO的支持
* 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:spring-jdbc.xml"})
public class TestSpringDao {
@Autowired
private IDepartmentDao deptDao;
@Test
public void testSpringDao(){
System.out.println(deptDao == null);
// 调用方法
Department dept = deptDao.getDepartmentByDeptNo(10);
System.out.println(dept);
}
}
6.1.7、删除和更新操作
package com.neuedu.springtest.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import com.neuedu.springtest.dao.IDepartmentDao;
import com.neuedu.springtest.entity.Department;
/**
* @author 时万绘
* Spring对DAO的支持
* 部门接口实现类
*/
@Repository
// @Repository连接数据库
public class DepartmentDaoImpl implements IDepartmentDao {
@Autowired
private JdbcTemplate jt;
/*
* 根据部门编号获取部门信息
*/
@Override
public Department getDepartmentByDeptNo(int deptNo) {
// 指定要执行的SQL语句
String sql = "select * from dept where deptNo = ?";
// 设置参数
Object[] params = {
deptNo};
// 返回结果集
return jt.queryForObject(sql, params,new RowMapper<Department>(){
@Override
public Department mapRow(ResultSet rs, int rowNum)
throws SQLException {
Department dept = new Department();
dept.setDeptNo(rs.getInt(1));
dept.setDeptName(rs.getString(2));
dept.setLocation(rs.getString(3));
return dept;
}
});
}
/*
* 获取全部部门信息
*/
@Override
public List<Department> getAllDepartments() {
// 指定SQL语句
String sql = "select * from dept";
return jt.query(sql, new RowMapper<Department>(){
@Override
public Department mapRow(ResultSet rs, int rowNum)
throws SQLException {
System.out.println("rowNum = " + rowNum);
Department dept = new Department();
dept.setDeptNo(rs.getInt(1));
dept.setDeptName(rs.getString(2));
dept.setLocation(rs.getString(3));
return dept;
}
});
}
/*
* 新增部门信息
*/
@Override
public int insertDepartment(Department dept) {
// 定义SQL语句
String sql = "insert into dept(dname,loc) values(?,?)";
// 设置SQL语句中指定的参数
Object[] args = {
dept.getDeptName(),dept.getLocation()};
// 执行SQL语句
return jt.update(sql,args);
}
/*
* 删除部门信息
*/
@Override
public int deleteDepartment(int deptNo) {
// 定义SQL语句
String sql = "delete from dept where deptNo = ?";
// 设置参数
Object[] params = {
deptNo};
return jt.update(sql,params);
}
/*
* 更新部门信息
*/
@Override
public int updateDepartment(Department dept) {
// 定义SQL语句
String sql = "update dept set dname = ?, loc = ? where deptNo = ? ";
Object[] params = {
dept.getDeptName(),dept.getLocation(),dept.getDeptNo()};
return jt.update(sql,params);
}
}
package com.neuedu.springtest.biz.impl;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.neuedu.springtest.dao.IDepartmentDao;
import com.neuedu.springtest.entity.Department;
/**
* @author 时万绘
* Spring对于DAO的支持
* 测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
"classpath:spring-jdbc.xml"})
public class TestSpringDao {
@Autowired
private IDepartmentDao deptDao;
/**
* 根据部门编号获取部门信息
*/
@Test
public void testSpringDao(){
System.out.println(deptDao == null);
// 调用方法
Department dept = deptDao.getDepartmentByDeptNo(10);
System.out.println(dept);
}
/**
* 查询所有的部门信息
*/
@Test
public void testGetAllDepartments(){
List<Department> depts = deptDao.getAllDepartments();
if(null != depts && depts.size() > 0){
depts.forEach(System.out :: println);
}
}
/**
* 添加部门信息
*/
@Test
public void testInsertDepartment(){
// 构建需要添加的部门对象
Department dept = new Department();
dept.setDeptName("SALES1");
dept.setLocation("DALIAN");
// 调用方法
int result = deptDao.insertDepartment(dept);
System.out.println(result > 0 ? "添加成功" : "添加失败");
}
/**
* 删除部门信息
*/
@Test
public void testDeleteDepartment(){
int deleteResult = deptDao.deleteDepartment(50);
System.out.println(deleteResult > 0 ? "删除成功" : "删除失败");
}
/**
* 更新部门信息
*/
@Test
public void testUpdateDepartment(){
// 构建需要添加的部门对象
Department dept = new Department();
dept.setDeptNo(50);
dept.setDeptName("SALES2222");
dept.setLocation("DALIANUpdate");
// 调用方法
int result = deptDao.updateDepartment(dept);
System.out.println(result > 0 ? "更新成功" : "更新失败");
}
}