导入的maven依赖
org.springframework
spring-webmvc
5.2.8.RELEASE
Spring优点
*Spring是一个开源的免费框架(容器)!
*Spring是一个轻量级的,非入侵式的框架!
*控制反装(IOC),面向切面编程(AOP)!
*支持事务的处理,对框架的整合的支持!
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
其次是:IOC(控制反转):实际上对象是由Spring创建,管理,装配!
===============================================================
使用Spring来创建对象时,在Spring这些都称为Bean
类型 变量名称 = new 类型();
Hello hello = new Hello();
id = 变量名
class = new 的对象
property 相当于给对象中的属性设置的一个值
<!-- 第一种:通过有参下标赋值! -->
<!-- <bean id="User" class="com.wang.pojo.User">-->
<!-- <constructor-arg index="0" value="王家俊学Spring!"/>-->
<!-- 默认通过无参构造创建 -->
<!-- <property name="name" value="王家俊"/>-->
<!-- 第二种:通过数据类型创建(如果参数有两个就不好设置了,所以不建议使用!)-->
<!-- <bean id="User" class="com.wang.pojo.User">-->
<!-- <constructor-arg type="java.lang.String" value="王家俊啦啦啦"/>-->
<!-- </bean>-->
<!--ref:引用Spring容器中创建好的对象
value: 具体的值,具体数据类型
-->
<!-- 第三种:直接通过参数名字赋值! -->
<bean id="User" class="com.wang.pojo.User">
<constructor-arg name="name" value="王家俊要回家!!"/>
</bean>
<!-- 当在创建bean的时候Spring就已经把他实例化了 -->
<!-- name也可以用作别名 可以空格分隔,逗号分隔,分号分隔 -->
<bean id="UserT" class="com.wang.pojo.UserT" name="User2 wangjiajun,u3;u4">
<property name="name" value="王家俊啦啦啦"/>
</bean>
<!-- 别名 -->
<alias name="User" alias="wangjiajun"/>
</beans>
property的几种注入方式:
<bean id="address" class="com.wang.pojo.Address">
<property name="addr" value="武汉"/>
</bean>
<bean id="name" class="com.wang.pojo.Student">
<!-- 第一种普通注入 -->
<property name="name" value="王家俊"/>
<!-- 第二种bean注入 -->
<property name="address" ref="address"/>
<!-- 第三种:数组注入 -->
<property name="books">
<array>
<value>王家俊学Java</value>
<value>王家俊学Spring</value>
<value>王家俊学Spring-Boot</value>
</array>
</property>
<!-- list -->
<property name="hobbys">
<list>
<value>听歌</value>
<value>看电影</value>
<value>啪啪啪</value>
</list>
</property>
<property name="card">
<map>
<entry key="爱好" value="睡觉"/>
<entry key="喜欢" value="女人"/>
<entry key="音乐" value="啦啦"/>
<entry key="游戏" value="无"/>
</map>
</property>
<property name="games">
<set>
<value>LOL</value>
<value>COC</value>
<value>BOB</value>
</set>
</property>
<!-- NULL值注入 -->
<property name="wife">
<null/>
</property>
<!--Properties
key:键值;
value:尖括号中间
-->
<property name="info">
<props>
<prop key="driver">20210630</prop>
<prop key="url">男</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
===============================================================
自动装配(Autowire):
<bean id="cat" class="com.wang.pojo.cat"/>
<bean id="dog" class="com.wang.pojo.dog"/>
创建一个猫和一个狗的实体类:
<bean id="person" class="com.wang.pojo.people" >
<property name="name" value="王家俊"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
</bean>
用普通的bean注入比较繁琐所以增加了自动注入的方式:
<bean id="person" class="com.wang.pojo.people" autowire="byName">
<property name="name" value="王家俊"/>
<!-- <property name="cat" ref="cat"/>-->
<!-- <property name="dog" ref="dog"/>-->
</bean>
注意:
byName:会自动在容器上下文中查找,和自己对象set方法后面对应的bean id!
byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!
缺点:ByType使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常
使用ByName会去spring容器中寻找是否有此字符串名称id的对象。
3. 如果有,就取出注入;如果没有,就报空指针异常。
Autowired(自动注入)
autowired里面有一个required默认为true,当
@Autowired(required = false)
private cat cat;
这么写的时候,该对象可以为null,否则不允许为空;也等价与Nullable
public people people(@Nullable String people){
return null;
}
另外:@Autowired是先通过bytype方式寻找,如果Type不唯一在通过ByName的方式寻找和resouces差不多
使用注解开发!
@Component组件,放在类上,说明被Spring管理,就是bean!另外,@Component组件有几个衍生注解
*dao【@Repository】
*service【@Service】
*controller【@Controller】他们四个是注解功能都是等价的
动态代理!!
我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
【聊聊AOP:纵向开发,横向开发】
、动态代理
动态代理的角色和静态代理的一样 .
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
基于接口的动态代理----JDK动态代理
基于类的动态代理--cglib
【InvocationHandler:调用处理程序】(这个方式是代理类的调用处理程序!先调用这个程序,再由这个程序执行代理类的方法(invoke)!)
Object invoke(Object proxy, 方法 method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接
口,它可以是代理类继承该方法的代理接口的超级接口。
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始
类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean
【Proxy : 代理】
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
代码实现
抽象角色和真实角色和之前的一样!
Rent . java 即抽象角色
//抽象角色:租房
public interface Rent {
public void rent();
}
Host . java 即真实角色
//真实角色: 房东,房东要出租房子
public class Host implements Rent{
public void rent() {
System.out.println("房屋出租");
}
}
ProxyInvocationHandler. java 即代理角色
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) throws
Throwable {
seeHouse();
//核心:本质利用反射实现!
Object result = method.invoke(rent, args);
fare();
return result;
}
//看房
public void seeHouse(){
System.out.println("带房客看房");
}
//收中介费
public void fare(){
System.out.println("收中介费");
}
}
Client . java
//租客
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();
}
}
//抽象角色:租房
public interface Rent {
public void rent();
}
核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!、
深化理解
我们来使用动态代理实现代理我们后面写的UserService!
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
public class ProxyInvocationHandler 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);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
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 methodName){
System.out.println("执行了"+methodName+"方法");
}
}
测试!
public class Test {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理对象的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); //设置要代理的对象
UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
proxy.delete();
}
}
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
公共的业务由代理来完成 . 实现了业务的分工 ,
公共业务发生扩展时变得更加集中和方便 .
一个动态代理 , 一般代理某一类业务
一个动态代理可以代理多个类,代理的是接口!
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现
程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的
一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使
得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。