目录
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的开源框架
Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
优点:
- Spring是一个开源的、免费的框架(容器)
- Spring是一个轻量级的、非侵入式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
控制反转(IOC)和面向切面编程(AOP)贯穿始终,是Spring学习的重中之重
导入maven依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 。
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
- Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
- 采用XML方式配置bean的时候,bean的定义信息和实现是分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
- 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IOC容器,实现方法是依赖注入(DI)
代码框架
编写一个UserDao接口
public interface UserDao {
public void getUser();
}
编写实现类,UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("User实现类");
}
}
编写UserService的接口
public interface UserService {
public void getUser();
}
编写UserServiceImpl实现类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
测试
@Test
public void MyTest(){
UserService service = new UserServiceImpl();
service.getUser();
}
那么随着UserDao实现类的增加,比如UserDaoMysqlImpl,UserDaoOracleImpl就不得不改变UserServiceImpl中的代码。很明显这样是不符合开闭原则的。
对UserServiceImpl做出如下改变:
public class UserServiceImpl implements UserService {
private UserDao userDao;
//利用set方法动态实现注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
- 之前,程序是主动创造对象!控制权在程序员手上
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!
这种思想,从本质上解决了问题,程序员不用再去管理对象的创建。系统的耦合性大大降低,可以更加专注在业务的实现上。这是IOC控制反转的原型!
1.编写实体类User
package com.kuang.pojo;
public class User {
private String name;
public User() {
System.out.println("user无参构造");
}
public User(String name) {
System.out.println("user有参构造");
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
2.配置beans.xml文件 ,并放在resource文件夹下
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
3.在beans.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用spring创建对象-->
<!-- User user=new User()-->
<!-- bean=对象-->
<!-- id=变量名-->
<!-- class=new 的对象-->
<!-- property 相当于给对象的属性赋值-->
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="user1"></property>
</bean>
</beans>
4.测试
import com.kuang.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取Spring的上下文对象
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
//我们的对象都在Spring中管理了,我们要使用直接去里面取出来就可以
//方式一:需要强转
User user =(User) context.getBean("user");
System.out.println(user);
//方式二:
//User user1 = context.getBean("user", User.class);
//System.out.println(user1);
}
}
System.out.println(user==user1)显示true,表明这两个user实际是同一个对象。
property方法本质是通过反射调用setName方法给属性进行赋值
<bean id="user" class="com.kuang.pojo.User">
<property name="name" value="user1"></property>
</bean>
通过构造器中参数的下标对属性进行赋值
<bean id="user2" class="com.kuang.pojo.User">
<constructor-arg index="0" value="user2"></constructor-arg>
</bean>
通过构造器中参数的类型进行赋值,由于可能有多个属性类型相同,故不推荐使用这种方法
<bean id="user3" class="com.kuang.pojo.User">
<constructor-arg type="java.lang.String" value="user3"></constructor-arg>
</bean>
通过构造器中参数的名称赋值
<bean id="user4" class="com.kuang.pojo.User" >
<constructor-arg name="name" value="user4"></constructor-arg>
</bean>
注意,如果属性不是java八大基本类型以及String类,需要将value改为ref
在配置文件加载的时候,容器中管理的对象就已经初始化了!
用来给对象设置别名,例如给user取别名newuser
<alias name="user" alias="newuser"/>
import:用于团队合作时,将多人的配置文件通过import合并为一个。
依赖注入(Dependency Injection,DI)。
依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .
上文已讲,见3.使用IOC创建对象
实体类Student,拥有各种类型的属性
package com.kuang.pojo;
import java.util.*;
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;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.toString() +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", games=" + games +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
<bean id="address" class="com.kuang.pojo.Address" scope="prototype">
</bean>
<bean id="student" class="com.kuang.pojo.Student">
<!--普通注入-->
<property name="name" value="小王"/>
<!--Bean注入-->
<property name="address" ref="address"></property>
<!--数组注入-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>三国演义</value>
</array>
</property>
<!--List注入-->
<property name="hobbys">
<list>
<value>游戏</value>
<value>电影</value>
</list>
</property>
<!--Map注入-->
<property name="card">
<map>
<entry key="身份证" value="3205"/>
<entry key="银行卡" value="9999"/>
</map>
</property>
<!--Set注入-->
<property name="games">
<set>
<value>lol</value>
<value>csgo</value>
<value>pubg</value>
</set>
</property>
<!--null注入-->
<property name="wife">
<null></null>
</property>
<!--Properties注入-->
<property name="info">
<props>
<prop key="学号">123456789</prop>
<prop key="性别">男</prop>
<prop key="root">local</prop>
<prop key="psw">123456</prop>
</props>
</property>
</bean>
导入如下约束:
重点了解singleton(单例模式)和prototype(原型模式)
Spring默认模式,Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。
<bean id="address" class="com.kuang.pojo.Address">
import com.kuang.pojo.Address;
import com.kuang.pojo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//Student student =(Student) context.getBean("student");
Address address1 = context.getBean("address", Address.class);
Address address2 = context.getBean("address", Address.class);
System.out.println(address2==address1);
}
}
输出结果:true。表明实际上address1和address2实际上是同一个对象,共享bean实例
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。
<bean id="address" class="com.kuang.pojo.Address" scope="prototype">
import com.kuang.pojo.Address;
import com.kuang.pojo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//Student student =(Student) context.getBean("student");
Address address1 = context.getBean("address", Address.class);
Address address2 = context.getBean("address", Address.class);
System.out.println(address2==address1);
}
}
输出结果:false。表明原型模式下,每次请求的bean对象都是不同的!
Sping中有三种自动装配方式 ,以下介绍第三种装配方式。
实体类Cat
package com.kuang.pojo;
public class Cat {
public void shout(){
System.out.println("miaomiao~");
}
}
实体类Person
package com.kuang.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class Person {
@Autowired
private Cat cat;
public Person(Cat cat) {
this.cat = cat;
}
public Person() {
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Override
public String toString() {
return "Person{" +
"cat=" + cat +
'}';
}
}
配置文件
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="person" class="com.kuang.pojo.Person"/>
测试
import com.kuang.pojo.Address;
import com.kuang.pojo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
}
输出结果:Person{cat=com.kuang.pojo.Cat@1ad282e0}
寻找所有set方法,例如setCat和setDog。获得首字母小写的属性名cat,dog。在spring容器中查找id为cat和dog的bean对象。如果有,取出并自动装配;没有则报空指针异常
在容器上下文中查找和set方法参数类型一致的bean,且必须唯一。否则会报错!
导入约束和注解
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
开启注解支持
<context:annotation-config/>
@Autowird是根据byName和byType自动识别的。如果ioc容器中只有一个该类型的对象则通过byType实现。否则通过byName
如果有多个同类型对象可以用如下方式指定:
什么是注解开发?就是用特定的注解代替beans.xml文件中注册对象的步骤。
1.配置环境,导入红框context约束
2.配置扫描包注解
<context:annotation-config/>
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.kuang.pojo"/>
3.在类上标上注解
package com.kuang.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//等价于<bean id="user" class="com.kuang.pojo.User"/>
//Component组件
@Component
public class User {
//等价于<property name="name" value="user1"/>
@Value("user1")
private String name;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
4.测试
@Test
public void test(){
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("beans.xml");
User user = (User) applicationContext.getBean("user");
System.out.println(user.name);
}
注意:注解开发对象默认的id为将首字母小写的类名,如User则默认为user
方法一:直接在属性上使用@value()注解
//等价于<property name="name" value="user1"/>
@Value("user1")
private String name;
方法二:如果有set方法,可以在set方法上使用@Value()注解
@Value("user1")
public void setName(String name) {
this.name = name;
}
使用注解@scope标明对象的作用域
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
//注册一个id="user" name="秦疆" 作用域为原型模式的bean
@Controller("user")
@Scope("prototype")
public class User {
@Value("秦疆")
public String name;
}
使用注解开发一定要开启扫描注解
<context:annotation-config/>
在理解AOP前,有必要先了解以下什么是代理模式 。因为AOP底层使用代理模式实现
静态代理角色分析
抽象角色 : 一般使用接口或者抽象类来实现
真实角色 : 被代理的角色
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
客户 : 使用代理角色来进行一些操作 .
举例说明上述不同角色:现有一个租房例子
抽象角色:
真实角色:
代理角色:代理真实角色,代理真实角色后,一般会做附属操作
客户 :
动态代理底层使用了反射实现,所以需要先了解反射机制。
抽象角色:
真实角色:
代理角色:代理真实角色,代理真实角色后,一般会做附属操作
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);
}
// proxy : 代理类 method : 代理类的调用处理程序的方法对象.
// 处理代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
//方法增强
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
客户类
//租客表示客户类
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理实例的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setRent(host); //将真实角色放置进去!
Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
proxy.rent();
}
}
一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
以下名词需要了解下:
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
1.导入依赖包
<dependency>
<groupId> org.aspectj</groupId >
<artifactId> aspectjweaver</artifactId >
<version> 1.9.4</version >
</dependency>
2.注册bean和配置aop
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.kuang.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>
3. 测试
1.自定义切入点
2注册bean和配置aop
1.写切面类并加以aspect注解
2.配置
3.测试
另外,_java类构造器和实例构造器
Vpublic interface UserView {void success(String data);void fail(String error);}Mpublic interface UserModel {interface CallBackListener { void success(String data); void fail(String er...
上一篇中的提到集合具体实现类在后续章节中逐一分析,本篇来分析项目中经常用到的数组列表(ArrayList)1 数组列表类关系 ArrayList主要实现了List、RandomAccess、Cloneable、Serializable接口,继承了AbstractList抽象类。 List接口定义了数组列表必须实现的方法 AbstractList实现了List中的通用的方法; RandomAc
//kruskal#include<iostream>#include<stdlib.h>#include<malloc.h>using namespace std;#define TOPMAX 60000#define MAX 100//邻接矩阵typedef struct _graph{ char vexs[MAX];...
MySQL是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 旗下公司。MySQL 流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。MySQL 是一种关联数据库管理系统..._1mz54m3yotl_ls3wlgkgxmw
将map集合存数据与取出数据全部放在一个类MapTest中,方便阅读与查看随便创建一个包,在包中新建一个class文件,(也可以不建包,直接新建一个class文件)新建class文件MapTest.java,代码如下:import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Ma..._java map put key value
工作10年以来,我一直在跟文字打交道。最初几年在办公室写材料,后来负责分管业务之后,也要经常写些东西,比如年终总结了、述职报告了、工作汇报了等,结果一年下来该敲打的文字也不少。按照领导的要求:“一个干部就应该张嘴能说、提笔能写”。工作久了有时也会遇到这种情况,比如前不久8月份我在湖南郴州出差,上级通知我需要发一通知,而我又没带笔记本,酒店里也没有。这种情况其实是不少见的,因为你不可能每次外出都带个笔记本。假如要放在五六年以前,就需要找一网吧,以前我就去过好几次。我现在还记得,为找网吧,到处打听半天跑了近2
无需得到返回值package paper2;import java.io.IOException;public class test_cmd { public static void main(String[] args) throws IOException, InterruptedException { String cmd_string = "echo 'sss'>test.txt"; // 执行的命令字符串 String[] cmd = new Stri_java怎么调用linux命令
首先明确的是编程过程中存在三种编码,一是操作系统编码,关系到open方法默认的编码格式,在windows为gbk;二是系统编码,指的是python编辑器的编码格式,python3为utf-8;三是python文件的头文件编码,影响python编辑器中自定义的字符串的编码格式。如果要在python编译器中正常输出,必须转为utf-8的格式,因为python3系统默认编码为utf-8。实质上pytho..._python3 文件头gbk
来自:http://blog.sina.com.cn/s/blog_13f7886010102x2iz.htmlAXI(Advanced eXtensible Interface)是一种总线协议,该协议是ARM公司提出的AMBA(Advanced Microcontroller Bus Architecture)3.0协议中最重要的部分,是一种面向高性能、高带宽、低延迟的片内总线。它的地址/控制和...
CSS样式: .icon-red, .icon-orange,.icon-yellow,.icon-blue,.icon-green { width:17px;height:12px;overflow:hidden;margin:auto; background:url(d_2.gif) no-repeat;
三维动漫设计开题报告动漫专业的同学们,大家知道怎么样书写自己的毕业论文吗?以下是小编精心准备的三维动漫设计开题报告,大家可以参考以下内容哦!三维游戏室内场景模型的应用与研究开题报告【1】一、与本项目有关的国内外研究情况、题目研究的目的和意义、主要内容、本课题创新之处、拟解决的问题:一、国内外研究现状:中国动画从创始至今,已走过八十年的漫长历史。而近十年来,随着互联网的日益普及,互联网游戏其独特的魅..._三维建模的目的与意义