Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
1.2 优点Spring是一个开源的免费的框架(容器)Spring是一个轻量级的、非入侵式的框架控制反转(IOC),面向切面编程(AOP)支持事务的处理,对框架整合的支持
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架
1.3 拓展Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;Spring Cloud是基于Spring Boot实现的;Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。 2、IOC
UserDao接口
public interface UserDao { void getUser();}
Dao 的实现类
public class UserDaoImpl implements UserDao{ @Override public void getUser() { System.out.println("默认获取用户的数据"); }}
UserService的接口
public interface UserService { void getUser();}
UserService的实现类
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public void getUser() { userDao.getUser(); }}
测试
@Testpublic void test(){ UserService service = new UserServiceImpl(); service.getUser();}
把Userdao的实现类增加一个 .
@Override public void getUser() { System.out.println("MySQl获取用户数据"); }
需要去service实现类里面修改对应的实现
private UserDao userDao = new UserDaoMySqlImpl(); @Override public void getUser() { userDao.getUser(); }
**结论:**我们要使需使用那个dao类 , 就要去service实现类里面修改对应的实现 、假设我们的这种需求非常大 , 这种方式就根本不适用了,因为 每次变动 , 都需要修改大量代码 、这种设计的耦合性太高了, 牵一发而动全身 .
如何解决?
我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .
private UserDao userDao; //利用set进行动态实现值的注入 public void setUserDao(UserDao userDao){ this.userDao = userDao; } @Override public void getUser() { userDao.getUser(); }
测试:
public static void main(String[] args) { //用户实际调用的是业务层,dao层他们不需要接触 UserServiceImpl userService = new UserServiceImpl(); userService.setUserDao(new UserDaoMysqlImpl()); userService.getUser(); }
结论:-
之前,程序员是主动创建对象,控制权在程序员手上使用set注入后,程序不在具有主动性,而是变成了被动接受的对象从本质上解决了问题,我们不用去管理对象的创建,系统耦合性大大降低,可以更加专注业务的实现,这就是IOC的原型
IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
3.HelloSpringpojo
public class Hello { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Hello{" + "name='" + name + ''' + '}'; }}
编写beans.xml
<?xml version="1.0" encoding="UTF-8"?>
测试
public class MyTest { public static void main(String[] args) { //获取Spring的上下文对象 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Hello hello = (Hello) context.getBean("hello"); System.out.println(hello.toString()); }}
结论:
4、IOC创建对象的方式控制:传统应用程序的对象由程序本身控制,使用Spring后由Spring来创建反转:程序本身不创建对象,而变成被动的接收对象依赖注入:就是利用set方法来进行注入的IOC是一种编程思想,由主动编程变被动接收要实现不同的操作,只需要在xml文件中进行修改对象由Spring来创建,管理,分配
使用无参构造
private String name; public User(){ System.out.println("User的无参构造!"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("name="+name); }}
使用有参构造的方式
public class User { private String name; public User(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void show(){ System.out.println("name="+name); }}
下标赋值
通过类型创建(不建议使用)
参数名
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了
5、Spring配置 5.1 别名5.2 Bean配置
一般用于团队开发,可以将多个配置文件合并为一个
依赖注入:Set注入
依赖:bean对象的创建依赖于容器注入:bean对象中的所有属性,由容器来注入
环境搭建
复杂类型
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
beans.xml
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.getName()); }}
完善注入信息
<?xml version="1.0" encoding="UTF-8"?>
可以使用p命名空间和c命名空间进行注入
userbean.xml
测试
@Test public void Test(){ ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml"); User user = context.getBean("user2",User.class); System.out.println(user); }
注意点:p命名和c命名空间不能直接使用,需要导入xml约束
```xml xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" ```
6.4 bean的作用域[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5NwjEWWP-1644740162813)(C:UsersliangAppDataRoamingTyporatypora-user-imagesimage-20220208153959223.png)]
单例模式(Spring默认机制)
原型模式:每次从容器中get的时候,都会产生一个新对象
其余的request,session,application这些只能在web开发中使用的
7、Bean的自动装配自动装配是Spring满足bean依赖一种方式Spring会在上下文中自动寻找,并自动给bean装配属性
Spring中的三种装配方式:
xml中显示的配置java中显示的配置隐式的自动装配bean【重要】 7.1 测试环境搭建:一个人有两个宠物
工具类
public class Dog { public void shout(){ System.out.println("wang~"); }}
public class Cat { public void shout(){ System.out.println("miao~"); }}
public class People { private Dog dog; private Cat cat; private String name; public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "People{" + "dog=" + dog + ", cat=" + cat + ", name='" + name + ''' + '}'; }}
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
测试
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); People people = context.getBean("people", People.class); people.getCat().shout(); people.getDog().shout(); }
7.2 ByName自动装配
小结:
ByName的时候,需要保证所有的bean的id唯一,并且这个bean需要和自己注入的属性的set方法的值一致ByType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自己注入的属性的类型一致 7.4 使用注解实现自动装配
使用注解须知:
导入约束。context约束
配置注解的支持 : context:annotation-config/
<?xml version="1.0" encoding="UTF-8"?>
@Autowired
直接在属性上使用即可,也可以在set方式上使用可以不用编写set方法,前提是自动装配的属性在IOC(Spring)容器中存在,且符合名字ByName
科普:
@Nullable 字段标记了这个注解,说明这个字段可以为null
public @interface Autowired { boolean required() default true;}
测试代码:
public class People { //如果显示了定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空 @Autowired(required = false)
@Qualifier
@Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
@Qualifier不能单独使用
测试:
@Autowired @Qualifier("dog22") private Dog dog; @Autowired @Qualifier("cat11") private Cat cat; private String name;
@Resource注解
@Resource(name = "dog2") private Dog dog; @Resource(name = "cat1") private Cat cat;
小结:
@Resource和@Autowired的区别:
都是自动装配的,都可以放在属性字段上@Autowired通过ByType的方式实现,并必须要求这个对象存在【常用】@Resource默认通过ByName的方式实现,如果找不到名字,则通过ByType实现,如果都找不到,则会报错【常用】执行顺序不同
@Autowired通过ByType的方式实现@Resource默认通过ByName的方式实现 8、使用注解开发
bean
//等价于
@Component:组件,放在类上,说明这个类被Spring管理了,就是bean
属性如何注入
//相当于
衍生注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
dao【@Repository】
service【@Service】
controller【@Controller】
它们的注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
自动装配
@Autowired 是根据类型自动装配的
@Nullable 字段标记了这个注解,说明这个字段可以为null
@Resource 通过装配名字,类型
作用域
@Component@Scope("singleton")public class User { //相当于
@scope
singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
小结
xml与注解:
XML可以适用任何场景 ,结构清晰,维护方便注解不是自己提供的类使用不了,开发简单方便
xml与注解最佳实践:
xml管理Bean
注解完成属性注入
要注意想让注解生效,就需要开启注解支持
实体类
public class User { @Value("pig") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + ''' + '}'; }}
配置文件
//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component//@Configuration代表这是一个配置类,就和我们之前看的beans.xml@Configuration@ComponentScan("com.lyd.pojo")@import(UserConfig2.class)public class UserConfig { //注册一个bean,就相当于我们之前写的一个bean标签 //这个方法的名字,就相当于bean标签中的id属性 //这个方法的返回值,就相当于bean标签中的class属性 @Bean public User getUser(){ return new User(); //就是返回要注入到bean的对象 }}
测试
public class MyTest { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class); User user = (User) context.getBean("getUser"); System.out.println(user.getName()); }}
10、代理模式两种代理模式:
静态代理动态代理 10.1 静态代理
角色分析:
抽象角色:一般会使用接口或抽象类真实角色:被代理角色代理角色:代理真实角色,代理后一般会做一些附属操作客户:访问代理对象的人
接口
public interface Rent { public void rent();}
真实角色
public class Host implements Rent{ @Override public void rent() { System.out.println("房东要出租房屋"); }}
代理角色
public class Proxy implements Rent{ private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { seeHouse(); host.rent(); heTong(); fee(); } public void seeHouse(){ System.out.println("看房"); } public void heTong(){ System.out.println("签合同"); } public void fee(){ System.out.println("缴费"); }}
客户端访问代理角色
public class Client { public static void main(String[] args) { Host host = new Host(); //代理 Proxy proxy = new Proxy(host); proxy.rent(); }}
代理模式的好处:
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务公共交给代理角色,实现业务的分工公共业务发生扩展的时候,方便集中管理
缺点:
一个真实角色产生一个代理角色,代码量会翻倍,开发效率会变低 10.2 动态代理
动态代理和静态代理角色一样动态代理的代理类是动态生成的,不是我们直接写好的动态代理分为两大类:
基于接口的动态代理基于类的动态代理
基于接口:JDK动态代理基于类:cglibjava字节码实现:javasist
需要了解两个类:Proxy:代理InvocationHandIer:调用处理程序
动态代理的好处:
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务公共交给代理角色,实现业务的分工公共业务发生扩展的时候,方便集中管理一个动态代理类代理的是一个接口,一般就是对应的一类业务一个动态代理类可以代理多个类,只要实现了同一个接口即可
代码示例:
ProxyInvocationHandIer
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyInvocationHandIer implements InvocationHandler { //被代理的接口 private Object target; public void setTarget(Object target){ this.target = target; } //生成得到代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //动态代理的本质,就是使用反射机制 log(method.getName()); Object result = method.invoke(target, args); return result; } public void log(String msg){ System.out.println("执行了"+msg+"方法"); }}
实体类
public interface Rent { public void rent();}
public class Host implements Rent { @Override public void rent() { System.out.println("房东要出租房屋"); }}
客户端
public class Client { public static void main(String[] args) { //真实角色 UserServiceImpl userService = new UserServiceImpl(); //代理角色:现在没有 ProxyInvocationHandIer pih = new ProxyInvocationHandIer(); //通过调用程序处理角色来处理我们要调用的接口对象 pih.setTarget(userService); UserService proxy = (UserService) pih.getProxy(); proxy.add(); }}
11、AOP使用Spring实现Aop
【重点】使用Aop,需要导入一个依赖包
方式一:使用Spring的API接口
public interface UserService { public void add(); public void delete(); public void update(); public void select();}
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 select() { System.out.println("查找一个用户"); }}
public class Log implements MethodBeforeAdvice { //method:要执行的目标对象的方法 //args:参数 //target:目标对象 public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"执行了"); }}
public class AfterLog implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue); }}
<?xml version="1.0" encoding="UTF-8"?>
public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理的是接口 UserService userService = context.getBean("userService", UserService.class); userService.add(); }}
方式二:自定义来实现AOP【主要是切面定义】
public class DiyPointCut { public void before(){ System.out.println("======方法执行前======"); } public void after(){ System.out.println("======方法执行后======"); }}
方式三:使用注解来实现
@Aspectpublic class AnnotationPointCut { @Before("execution(* com.lyd.service.UserServiceImpl.*(..))") public void before(){ System.out.println("======方法执行前======"); } @After("execution(* com.lyd.service.UserServiceImpl.*(..))") public void after(){ System.out.println("======方法执行后======"); } //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点 @Around("execution(* com.lyd.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); Signature signature = jp.getSignature(); //获得签名 System.out.println("signature"+signature); Object proceed = jp.proceed(); //执行方法 System.out.println("环绕后"); }}
12.整合Mybatis 12.1 回忆Mybatis步骤:
导入相关jar包
junitmybatismysql数据库spring相关的aop织入mybatis-spring
编写核心配置文件
<?xml version="1.0" encoding="UTF8" ?>
编写接口
public interface UserMapper { public List
编写Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
测试
@Test public void test() throws IOException { String resources = "mybatis-config.xml"; InputStream in = Resources.getResourceAsStream(resources); SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in); SqlSession sqlSession = sessionFactory.openSession(true); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List
配置文件
<?xml version="1.0" encoding="UTF-8"?>
配置接口实现类
public class UserMapperImpl implements UserMapper{ //在原来我们的所有操作都使用sqlSession来执行,现在都使用SqlSessionTemplate private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public List
测试
@Test public void test() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } }
13、声明式事务 1、回顾事务要么都成功,要么都失败十分重要,涉及到数据一致性确保完整性和一致性
事务的ACID原则:
原子性一致性隔离性
多个业务可能操作同一个资源。防止数据损坏 持久性
事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中 2、spring中的事务管理
声明式事务:AOP编程式事务:需要在代码中,进行事务的管理
声明式事务
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
Mapper
public interface UserMapper { public List
<?xml version="1.0" encoding="UTF-8" ?>
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{ public List