一.Spring的简介(本质是容器)
Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
Spring官方文档
二、对IOC【控制反转】,DI【依赖注入】的理解
IOC(Inversion of Control,控制反转)是Spring实现的核心,IOC实现对应用程序对象的控制反转,控制反转并不是顺序发生变化,而是在应用程序中创建对象角色的反
转,将原本是由应用程序创建对象的任务在IOC容器创建了,这就是IOC控制反转【动态的想客户端提供所需要的其他对象】。
DI,(Dependency injection 依赖注入【被注入对象依赖IoC容器配置依赖对象】),DI常与IOC在Spring中搭配使用,DI在Spring框架中扮演着为IOC容器中创建的对象进行
外部资源注入角色,使得代码的工作量变少,
三·、静态代理与动态代理的理解
静态代理:手动去创建一个代理类,在不改变源码的前提下来对基本业务进行横向扩充,代理模式本质是媒介,真实角色将业务交给代理类来调用,客户端访问只需要通过代理
类来进行访问,但是静态代理模式具有一定的局限性,每承担一个真实角色的业务,就需要创建一个代理类,造成资源的浪费,代码的复用性降低。
动态代理:使用者通过创建一个类来继承InvocationHandler接口,借助于Proxy类得到newProxyInstance(类加载器,被代理的接口,本身的类)获取代理类;接下来是处理结果 invoke方法可以帮我们处理结果,这样我们一个动态代理类获取就已经完成了,客户端就可以通过它来知道相应的业务;动态代理底层是利用JDK反射来实现的。
反射的概念:(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
四、AOP面向切面编程的感悟
Spring框架中的AOP,是对于在实际的业务需求下,我们在不改变代码的纵向运行的条件下,对业务实现横向扩展,与代理模式不同的是,针对于某个类或者某个包,称之为连接点;我们创建一个类叫做扩展业务类,其就是切面;再进行一个通知操作,作用是将切面中的方法,引入到切点中【这步是在IOC中实现的】;切点中得到切面后是织入连接点上,这样业务的横向发展完成了,同时这个操作也称之为AOP即为面向切面编程,这种思想是重要的!
五.Spring的配置文件
<?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">
<!-- import 导入其他配置文件合并为一个总配置文件applicationContext(全名)
一般用于团队开发,
-->
<import resource="beans.xml"/>
</beans>
六.DI注入(applicationContext.xml配置文件中进行注入)
1.DI-构造器器注入
<?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创建对象,在spring中统称Bean
对象由Spring创建,
对象属性由Spring设置
正常情况:类型 变量名=new 类型();
使用spring:id=变量名(唯一标识符)
class=new 的对象(bean对象的全限定类名:包名+类名)
name:取别名,可以同时对一个对象取多个别名
property:对象属性值得设置
-->
<!-- 默认以无参构造器 new的对象-->
<bean id="Man" class="com.gec.pojo.Man" name="man">
<property name="name" value="Spring"/>
</bean>
<!-- 有参构造器 new对象-->
<bean id="user" class="com.gec.pojo.User">
<!-- 第一种:下标赋值-->
<!-- <constructor-arg index="0" value="小明"/>-->
<!-- 第二种:通过类型创建,若有相同类型的属性不是容易处理,(不建议使用)-->
<!-- <constructor-arg type="java.lang.String" value="小红"/>-->
<!-- 第三种:直接通过实体类中参数名来设置-->
<constructor-arg name="name" value="小花"/>
</bean>
<bean id="usert" class="com.gec.pojo.UserT">
</bean>
</beans>
2,DI-set方法注入(不同数据的注入方式)
三国演义 水浒传 西游记 红楼梦 吃饭 睡觉 大豆豆 绝地求生 LOL QQ农场 毛毛 男 18 <bean id="address" class="com.gec.pojo.Address">
<property name="address" value="狗熊岭"/>
</bean>
3.测试
// 提供给ApplicationContext构造函数的位置路径是资源字符串,
// 这些资源字符串使容器可以从各种外部资源(例如本地文件系统,Java CLASSPATH等)加载配置元数据
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 对象都被在spring中被代理理了, 我们使用的时候只需要从Spring容器中取出即可
//使用时取出的是配置文件Bean中设置的id属性值,直接get就ok
//在getBean的时候Man对象属性就已经初始化了
Man man = (Man) context.getBean("man");
System.out.println(man.toString());
七.Bean的作用域
a.singleton单例模式【Spring默认的机制】
图解:
代码实现:
<bean id="Man" class="com.gec.pojo.Man" name="man" scope="singleton">
<property name="name" value="Spring"/>
</bean>
b.prototype原型默认【每次从容器中get时都会产生一个对象】
图解:
代码实现:
<bean id="Man" class="com.gec.pojo.Man" name="man" scope="prototype">
<property name="name" value="Spring"/>
</bean>
八、Spring的自动装配
1.自动装配Bean
(1).自动装配是Spring满足bean依赖注入的一种方式
(2)Spring会在上下文中自动寻找,去装配bean的属性
2.隐式的自动装配bean【重点】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.gec.pojo.Cat"/>
<bean id="dog" class="com.gec.pojo.Dog"/>
<!--
autowire:根据那种要求进行自动装配
byName:autowire会在上下文中自动寻找与People下set方法后面值对应的bean id【保证bean id 唯一】
<bean id="people" class="com.gec.pojo.People" autowire="byName">
<property name="name" value="小妹"/>
</bean>
=================================================================== ===================
byType:autowire会在上下文中自动寻找与People中封装对象属性相同的bean【保证bean中属性对象的class 唯一】
<bean id="people" class="com.gec.pojo.People" autowire="byType">
<property name="name" value="小妹"/>
</bean>
-->
<bean id="people" class="com.gec.pojo.People" autowire="byType">
<property name="name" value="小妹"/>
</bean>
###3.注解实现自动装配 dao层: @Repository组件的意思 代表将改=该类注册到Spring中,装配到bean中 实体类:
@Component【组件】等价于
<bean id="user" class="com.gec.pojo.User"/>
@Value【组件】等价于 <property name="name" value="豆豆"/>
service层:
@Service代表将改=该类注册到Spring中,装配到bean中
controller层:
代表将改=该类注册到Spring中,装配到bean中
@Controller
通过注解的方式来实现配置文件的操作:
//@Configuration代表的是一个配置类和Beans.xml相等
// 也会被注册到Spring中因为本质就是@Component
//
@Configuration
//监听这个类中全部的注解
@ComponentScan(“com.gec.pojo”)
//导入其他使用注解操作的bean
@Import(CatConfig.class)
public class Dogconfig {
// @Bean:注册一个bean代表一个<bean><bean/>标签
// 方法名就是bean id
// 返回值代表bean class
//
@Bean
public Dog dog(){
//返回的就是注入对象
return new Dog();
}
}
2.静态代理模式
图示:
静态代理角色分析:
抽象的角色:一般是实现类或者接口中介与房东共同的目的出租房子
客户:等价于租客,是客户,来租房子的
代理角色:代理真是角色,=中介
真实角色:被代理的角色房东,出租房子 (一般用于去实现接口)
静态代理模式的优缺点:
优点:代理模块用来处理公共业务,方便真实角色去处理自己本身对应的业务,
代理模式实现业务分离,便于管理
缺点:一个真实角色会需要一个代理对象,多个真实角色就会需要多个代理对象,开发效率低!
3.动态代理模式(动态的生成proxy代理类【媒介】)
动态代理和静态代理的角色一样
动态代理是动态生成的
动态代理的实现分为两种:一种是基于接口实现,另外一种是基于类来实现
基于接口实现=========JDK动态代理
基于类实现==========cglib
java字节码实现===javasist
(1).使用的相关类
a.Proxy
InvocationHandler (Java Platform SE 8 )调用处理程序
(2).动态代理对象的生成
a、通过Proxy类中的newProxyInstance方法来生成代理类
该方法中有三个参数:类加载器,代理对象实现的接口,调用处理程序
public Object getProxy(){
//newProxyInstance中第一个(类加载器)和第三个参数是固定(目前) 只需要改变第二个参数即可
//ren.getClass().getInterfaces()=获取被代理的接口
return Proxy.newProxyInstance
(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
b、处理代理实例,并返回一个结果; InvocationHandler (Java Platform SE 8 )当在与之关联的代理实例上调用方法时,将在调用处理程序中调用此方法。
该方法中有三个参数:proxy调用该方法的代理实例,method所述方法对应调用代理实例上接口实例的方法的实例
args包含方法调用传递代理实例参数值的对象阵列,或者如果接口方法没有参数传递的为null值,包括原始类型
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是反射机制实现的
Object reuslt = method.invoke(target, args);
return reuslt;
}
c、测试
//创建的房东对象即是真实对象
master mas=new master();
//此时还没有创建代理类
ProInvocationHandler pih = new ProInvocationHandler();
//通过调用处理程序来处理真实被代理的对象(角色房东),将真实对象入参到setRen方法中,来处理;
pih.setRen(mas);
//proxy是动态生成的代理对象
//Ren是.代理对象实现的接口
Ren proxy = (Ren) pih.getProxy();
proxy.lease();
九、AOP简介
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 注册bean-->
<bean id="userImpl" class="com.gec.service2.UserServiceImpl2" />
<bean id="beforlog" class="com.gec.log.BeforLog"/>
<bean id="afterlog" class="com.gec.log.AfterLog"/>
方式一:通过SpringAPI接口来实现的AOP
<!-- 配置aop-->
<!--<!– 需要导入aop及aop约束–>-->
<!-- <aop:config>-->
<!--<!–-->
<!-- 配置切入点;expression:要切入的切点,(执行的位置)-->
<!-- execution(* 插入的具体位置.*【这个类中所有方法】 )-->
<!-- execution(* com.gec.service2.UserServiceImpl2.*(..))-->
<!--–>-->
<!-- <aop:pointcut id="pointcut" expression="execution(* com.gec.service2.UserServiceImpl2.* (..))"/>-->
<!--<!– 执行环绕–>-->
<!-- <aop:advisor advice-ref="beforlog" pointcut-ref="pointcut"/>-->
<!-- <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>-->
<!-- </aop:config>-->
方法二:通过自定义切面 来实现AOP
<!-- 注册自定义的一个类 是横向延伸的一个业务操作类-->
<bean id="diy" class="com.gec.log.diy"/>
<aop:config>
<!-- 引入切面 -->
<aop:aspect ref="diy">
<!-- 是要引入切面的切点位置-->
<aop:pointcut id="pointcut" expression="execution(* com.gec.service2.UserServiceImpl2.* (..))"/>
<!-- 通知向切点加入的方法或业务-->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
方法三:
//方法三利用注解来实现AOP
@Aspect//标记为一个切面
public class Aonntist {
//执行前的注解 切点
@Before(“execution(* com.gec.service2.UserServiceImpl2.* (…))”)
public void before(){
System.out.println(“=============method run before”);
}
//执行后 切点
@After(“execution(* com.gec.service2.UserServiceImpl2.* (…))”)
public void after(){
System.out.println(“=============method end after”);
}
@Around(“execution(* com.gec.service2.UserServiceImpl2.* (…))”)
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println(“环绕前”);
Object proceed = jp.proceed();
System.out.println(proceed);//方法的返回
Signature signature = jp.getSignature();//签名
System.out.println(“执行方法的签名:” +signature);
System.out.println(“环绕后”);
}
事务回顾和Spring式事务
事务:
ACID:原子性,一致性,隔离性,持久性;
分为两种:编程式事务【会改变源码】和spring式事务【通过动态代理来实现】
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="transaction" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.gec.mapper.*.*(..) )"/>
<aop:advisor advice-ref="transaction" pointcut-ref="txPointcut"/>
</aop:config>