Spring:春天—>给软件行业带来了春天!
2002年,首次推出了Spring框架的雏形:interface21框架!
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
SSH:Struct2 + Spring + Hibernate
SSM:SpringMVC + Spring + Mybatis!
官网:https://spring.io/
官方下载地址:https://repo.spring.io/release/org/springframework/spring/
GitHub:https://github.com/spring-projects/spring-framework
spring依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
spring整合jdbc依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
在Spring官网有这样一句话:现代化的Java开发,说白了就是基于Spring的开发!
因为现在大多数攻速都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!
弊端:发展了太久,违背了原来的理念,配置十分繁琐,人称:配置地狱!
1.UserDao业务接口
2.UserDaoImpl实现类
3.UserService业务接口
4.UserServiceImpl业务实现类
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分大,修改代价将十分昂贵
我们使用一个Set接口实现,已经发生了革命性的变化!
private UserDao userDao;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
这种思想,从本质上解决了问题,我们程序猿不再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注的在业务的实现上!这是IOC的原型
之前:
现在:
控制反转IOC是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中,我们使用面向对象编程,对象的创建和对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后,将对象的创建转移给第三方,个人认为所谓的控制反转就是:获得依赖对象的方式反转了!
采用XML方式配置Bean的时候,Bean的定义信息和实现是分离的,而采用注解的方式可以把两者合二为一,Bean的定义信息直接以注解的形式定义在实现类中,从而打到零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定的对象。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)。
public static void main(String[] args) {
//获取Spring的上下文对象!
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
思考问题
Hello对象是谁创建的?
Hello对象是由Spring创建的
Hello对象的属性是怎么设置的?
Hello对象的属性是由Spring容器设置的
这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序是由程序本身控制创建的,使用Spring之后,对象由Spring来创建
反转:程序本身不创建对象,而变成被动的接收对象
依赖注入:就是利用set方法来进行注入
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一个底层源码
OK!到了现在,我们彻底不用再去程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话:对象由Spring来创建,管理,装配!
1、使用无参构造创建对象,默认!
2、假设我们要使用有参构造创建对象
<!--第一种,下标赋值-->
<bean id="user" class="pojo.User">
<constructor-arg index="0" value="孤生"/>
</bean>
<!--第二种,通过类型创建,不建议使用-->
<bean id="user" class="pojo.User">
<constructor-arg type="java.lang.String" value="孤生"/>
</bean>
<!--直接通过参数名来设置-->
<bean id="user" class="pojo.User">
<constructor-arg name="name" value="孤生"/>
</bean>
总结:在配置文件加载时,Spring容器中管理的对象就已经被实例化了,不管是否get!
<alias name="user" alias="u2"/>
<bean id="userT" class="pojo.User" name="user2 user3,user4">
<constructor-arg name="name" value="孤生"/>
bean>
<import resource="bean.xml"/>
这个import,一般用于团队开发使用,他可以将多个配置文件,导入合并成为一个
假设,现在项目中有多人开发,这三个人负责不同类的开发,不同的类需要注册到不同的bean中,我们可以利用import将所有人的bean文件合并为一个总的
使用的时候,直接用总的配置就可以了
前面已经讲过了
依赖注入: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> hobbys;
private Map<String,String> card;
private Set<String> games;
private String wife;
private Properties info;
<bean id="address" class="pojo.Address">
<property name="address" value="西安"/>
bean>
<bean id="student" class="pojo.Student">
<property name="name" value="孤生"/>
<property name="address" ref="address"/>
<property name="books">
<array>
<value>红楼梦value>
<value>三国演义value>
<value>水浒传value>
<value>西游记value>
array>
property>
<property name="card">
<map>
<entry key="学生证" value="1234635869574"/>
<entry key="身份证" value="1564613216546464"/>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>COCvalue>
<value>BOBvalue>
set>
property>
<property name="hobbys">
<list>
<value>唱value>
<value>跳value>
<value>Rapvalue>
list>
property>
<property name="wife">
<null/>
property>
<property name="info">
<props>
<prop key="url">jdbc........prop>
<prop key="drive">com........prop>
<prop key="username">rootprop>
<prop key="password">rootprop>
props>
property>
bean>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
String s = student.toString();
System.out.println(s);
}
}
我们可以使用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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="[email protected]"/>
bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="[email protected]"/>
beans>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
bean>
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="[email protected]"/>
beans>
注意点:p命名空间和c命名空间不能直接使用,需要导入xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
1、单例模式(Spring默认机制)
<bean id="student" class="pojo.Student" scope="singleton">
2、原型模式:每次从容其中get的时候,都会产生一个新对象!
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
3、其余的request、session、application这些只能在web开发中使用!
在Spring中有三种装配方式:
<bean id="cat" class="pojo.cat"/>
<bean id="dog" class="pojo.dog"/>
<bean id="person" class="pojo.person" autowire="byName">
<property name="name" value="孤生呀"/>
bean>
<bean class="pojo.cat"/>
<bean class="pojo.dog"/>
<bean id="person" class="pojo.person" autowire="byType">
<property name="name" value="孤生呀"/>
bean>
小结:byName,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致!
byType,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!
jdk1.5支持的注解,Spring2.5就支持了!
要使用注解须知:
导入约束:context约束
配置注解的支持:
<context:annotation-config/>
完整配置:
<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)容器中存在,并且满足byName!
测试代码
public class person {
private String name;
//如果显式的定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
@Autowired(required = false)
private cat cat;
@Autowired
private dog dog;
}
如果**@Autowired自动装配的环境比较复杂,无法通过一个注解[@Autowired**]来完成的时候、我们可以使用@Qualifier(value = “xxx”) 去配合**@Autowired**使用,指定一个唯一的bean对象注入!
@Resource注解
public class person {
private String name;
@Resource(name = "cat22")
private cat cat;
@Resource
private dog dog;
}
bean
属性如何注入
在类型名或者set方法上@Value(“xxx”)
衍生的注解
@Component有几个衍生注解,我们在web开发时,会按照MVC三层架构分层
这四个注解功能是一样的,都是代表将某个类注册到Spring中。装配Bean
自动装配
详细见上面
作用域
@Component
@Scope(“作用域”)
小结
xml与注解:
xml与注解最佳实践:
我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig是Spring的一个子项目,在Spring 4之后,它成为了核心内容!
实体类
public class User {
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
@Value("孤生")
public void setName(String name) {
this.name = name;
}
}
配置类
@Configuration//这个也会被Spring容器托管,注册到容器中,因为他本来就是个组件
public class JavaConfig {
@Bean
public User getUser(){
return new User();
}
}
测试类
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class);
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser.getName());
}
}
为什么要学习代理模式?
因为这就是SpringAOP的底层
面试必问 [SpringAOP 和 SpringMVC]
代理模式分类:
角色分析:
代理模式的好处:
代理模式的缺点:
Demo:
抽象角色类:
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
真实角色类:
//真实对象
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("查询了一个用户");
}
}
代理对象类:
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+"方法");
}
}
测试类:
public class Client {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy userServiceProxy = new UserServiceProxy();
userServiceProxy.setUserService(userService);
userServiceProxy.add();
}
}
动态代理和静态代理的角色一样
动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
需要了解两个类:
动态代理实现:
public class InvocationHandler implements java.lang.reflect.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);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object invoke = method.invoke(target, args);
return null;
}
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}
测试程序:
public class Client {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在
InvocationHandler pih = new InvocationHandler();
//设置要代理的对象
pih.setTarget(userService);
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
}
}
[重点]使用AOP,需要导入一个依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
方式一:使用Spring的API接口 [主要SpringAPI接口实现]
方式二:自定义来实现AOP [主要是切面定义]
方式三:使用注解实现!
步骤:
1、导入相关jar包
2、编写配置文件
3、测试
事务ACID原则: