Spring5-2020.10.20
面向bean(pojo 普通的java类)的编程
1,IOC
ioc:控制反转 (DI:依赖注入)
优点
1,spring是一个开源免费的框架,容器
2,spring是一个轻量级的框架,非侵入式的
3,控制反转IOC,面向切面
4,对事务的支持,对框架的支持
总之:
spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)
1.1,IOC基础
分析实现
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qnTddG0A-1605087301300)(C:\Users\zp\AppData\Roaming\Typora\typora-user-images\image-20201105093611039.png)]
dao层:
package com.zp.dao;
public interface Userdao {
public void getUser();
}
Userdaoimpl
package com.zp.dao;
public class Userdaoimpl implements Userdao {
@Override
public void getUser() {
System.out.println("获取用户数据!");
}
}
UserdaoMysql:
package com.zp.dao;
public class UserdaoMysql implements Userdao {
@Override
public void getUser() {
System.out.println("获取mysql用户数据!");
}
}
UserdaoOrcaleimpl:
package com.zp.dao;
public class UserdaoOrcaleimpl implements Userdao{
@Override
public void getUser() {
System.out.println("获取Orcale数据!");
}
}
Service层:
UserService:
package com.zp.Service;
public interface UserService {
public void getUser();
}
UserServiceimpl:
package com.zp.Service;
import com.zp.dao.Userdao;
import com.zp.dao.UserdaoMysql;
import com.zp.dao.UserdaoOrcaleimpl;
import com.zp.dao.Userdaoimpl;
public class UserServiceimpl implements UserService {
private Userdao userdao;
//使用set方法
public void setUserdao(Userdao userdao){
this.userdao=userdao;
}
@Override
public void getUser() {
userdao.getUser();
}
}
resource:
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">
<!--
ref;是相当引用spring容器中创建好的对象
values;是具体的值,基本数据类型
-->
<bean id="Userdaoimpl" class="com.zp.dao.Userdaoimpl"/>
<bean id="UserdaoMysql" class="com.zp.dao.UserdaoMysql"/>
<bean id="UserdaoOrcaleimpl" class="com.zp.dao.UserdaoOrcaleimpl"/>
<bean id="UserServiceimpl" class="com.zp.Service.UserServiceimpl">
<property name="userdao" ref="UserdaoOrcaleimpl"/>
</bean>
</beans>
测试:
import com.zp.Service.UserService;
import com.zp.Service.UserServiceimpl;
import com.zp.dao.UserdaoMysql;
import com.zp.dao.UserdaoOrcaleimpl;
import com.zp.dao.Userdaoimpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
/*UserServiceimpl Service = new UserServiceimpl();
((UserServiceimpl) Service).setUserdao(new Userdaoimpl());
Service.getUser();*/
//获取ApplicationContext;拿到spring的容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean
UserService userdaoimpl = (UserService) context.getBean("UserServiceimpl");
userdaoimpl.getUser();
}
}
注意点:
1,在service层的实现类中注册bean
<bean id="Userdaoimpl" class="com.zp.dao.Userdaoimpl"/>
<bean id="UserdaoMysql" class="com.zp.dao.UserdaoMysql"/>
<bean id="UserdaoOrcaleimpl" class="com.zp.dao.UserdaoOrcaleimpl"/>
<!--<注册bean-->
<bean id="UserServiceimpl" class="com.zp.Service.UserServiceimpl">
<property name="userdao" ref="UserdaoOrcaleimpl"/>
</bean>
ref;是相当引用spring容器中创建好的对象
values;是具体的值,基本数据类型
重点理解:
控制反转(inversion of control)是一种通过描述(xml或者注解)并通过第三方去生产或者获取特定对象的方式。在Spring中是实现控制反转的方法是依赖注入(Dependency Injection,
DI)
1.2,概述及IOC的基本思想
Hello,spring
首先导入依赖,jar包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
2,编写实体类User
package com.zp.pojo;
public class User {
private String name;
public User() {
System.out.println("user无参构造方法");
}
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("show,name:"+name);
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用spring来创建对象,这些对象统称bean
类型 变量名 = new 类型();
id=变量名
class=new的对象
property相当于给变量的属性赋值
-->
<bean id="hello" class="com.zp.pojo.Hello">
<property name="str" value="spring"/>
</bean>
<bean id="user" class="com.zp.pojo.User">
<property name="name" value="zp"/>
</bean>
</beans>
4,测试
import com.zp.pojo.Hello;
import com.zp.pojo.User;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class myTest {
public static void main(String[] args) {
//获取spring的上下文对象
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在spring中管理了,我们使用对象的话,直接在里面取出来就是了
User hello = (User) context.getBean("user");
//Hello hello =(Hello)context.getBean("hello");
hello.show();
System.out.println(hello.toString());
}
}
理解:
hello spring,demo的编写就是为了体会到,对象是
在xml文件中创建,需要使用对象的时候直接在spring容器中取出,
通过:new ClassPathXmlApplicationContext context。通过来获取spring上下文:spring Context,来使用bean
这就是控制反转:
· 控制:控制对象的创建
· 反转:程序本身不创建对象,而而是用来接受对象。
依赖注入:
就是利用set方法来进行注入
ioc是一种编程思想,由主动的编程变成被动的接收
1.3,beans.xml编写方式
<bean id="user" class="com.zp.pojo.User">
<property name="name" value="zp"/>
</bean>
注意点:
使用spring来创建对象,这些对象统称bean
类型 变量名 = new 类型();
id=变量名
class=new的对象
property相当于给变量的属性赋值
三种使用构造器创建bean的方式:
第一种根据index参数下标设置:
<!-- 第一种根据index参数下标设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- index指构造方法 , 下标从0开始 -->
<constructor-arg index="0" value="kuangshen2"/>
</bean>
第二种根据参数名字设置:
<!-- 第二种根据参数名字设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<!-- name指参数名 -->
<constructor-arg name="name" value="kuangshen2"/>
</bean>
第三种根据参数类型设置:
<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.kuang.pojo.UserT">
<constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>
结论:在配置文件加载的时候,其中的管理的对象已经初始化了
Spring 配置:
别名:
<!--设置别名:在获取Bean的时候可以使用别名获取-->
<alias name="userT" alias="userNew"/>
Bean的配置:
import:
团队的合作通过import实现:
<import resource="{path}/beans.xml"/>
ioc的实现
1,编写实体类User
package com.zp.pojo;
public class User {
private String name;
public User(String name) {
this.name = 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);
}
}
2,编写配置文件:
<?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">
<import resource="beans.xml"/>
</beans>
<?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">
<!--
id:bean的唯一标识符,相当于对象名
class:bean对应的全限定名,包名+类名
name:也是别名,而且还可以同时起多个别名,别名之间还可以用“,”,以及“空格”
-->
<bean id="user" class="com.zp.pojo.User">
<property name="name" value="zp"/>
</bean>
<bean id="user2" class="com.zp.pojo.User" name="user3">
<constructor-arg value="zp2" name="name"/>
</bean>
</beans>
<?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">
<!--
id:bean的唯一标识符,相当于对象名
class:bean对应的全限定名,包名+类名
name:也是别名,而且还可以同时起多个别名,别名之间还可以用“,”,以及“空格”
-->
<bean id="user" class="com.zp.pojo.User">
<property name="name" value="zp"/>
</bean>
<bean id="user2" class="com.zp.pojo.User" name="user3">
<constructor-arg value="zp2" name="name"/>
</bean>
</beans>
3,测试:
import com.zp.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class myTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) context.getBean("user3");
user.show();
}
}
2,依赖注入DI
1,Dependency Injection
概念:
· 依赖注入(dependency injection)di
· 依赖:指Bean对象的创建依赖于容器,Bean对象的依赖资源
· 注入:指Bean对像所依赖的资源,由容器来设置和装配
构造器注入:
set注入(重点)
要求被注入的属性,必须要有set方法,如果属性是boolean类型,没有set方法,是is
1,常量注入
<bean id="address" class="com.zp.pojo.Address">
<property name="address" value="洛阳"/>
</bean>
2,Bean注入
<bean id="student" class="com.zp.pojo.Student">
<!--第一种,普通值注入,value-->
<property name="name" value="zp"/>
<!--第二种,bean注入,ref是引用类型-->
<property name="address" ref="address"/>
3,数组注入
<!--第三种,数组-->
<property name="books">
<array>
<value>红楼梦</value>
<value>三国演义</value>
<value>水浒传</value>
<value>西游记</value>
</array>
</property>
4,集合注入
<!--第四种,集合-->
<property name="hobbys">
<list>
<value>网易云</value>
<value>lol</value>
<value>spring</value>
</list>
</property>
5,Map注入
<!--第五种,Map-->
<property name="cards">
<map>
<entry key="身份证" value="11111111111111111111111"/>
<entry key="一卡通" value="2222222222"/>
</map>
</property>
6,set注入
<!--set-->
<property name="games">
<set>
<value>gta5</value>
</set>
</property>
7,null注入
<!--null-->
<property name="wife">
<null/>
</property>
也可是使用注解:@Nullable
8,properties注入
<!--properties-->
<property name="info">
<props>
<prop key="学号">2222</prop>
</props>
</property>
p命名和c命名注入
<!--<scope:作用域-->
<!--<p命名注入和c命名注入
p命名注入:就是property
c命名注入:就是构造器注入;construct,使用是要写有参构造器
-->
<bean id="user" class="com.zp.pojo.User" p:age="18" p:name="张朋"/>
<bean id="user2" class="com.zp.pojo.User" c:age="18" c:name="张朋2" scope="prototype"/>
2,注意点:
使用c命名和p命名需要有无参构造
p命名注入:就是property
c命名注入:就是构造器注入;construct,使用是要写有参构造器
Bean的作用域:scope
Bean:就是IOC容器初始化,装配,管理的对象
5种作用域:
**singleton:**单例类型,IOc容器中仅有一个bean(共享)
**prototype:**原型类型,就是一个bean定义对应对多个对象实例。每次调用时都会执行一个newbean(),
**request:**作用域仅在web的spring ApplicationContext情形下有效
**session:**表示一个bean的作用域为:session,在一个http session中,一个bean定义对应一个实例。该作用域仅在基于web的spring ApplicationContext情形下有效。
3,自动装配
Bean的自动装配
自动装配说明
· 自动装配是使用spring满足bean依赖的一种方法
· spring会在应用上下文中为某个bean寻找其依赖的bean。
Spring中bean有三种装配机制,分别是:
1,在xml中显式配置
2,在java中显式配置
3,隐式的bean发现机制和自动装配
自动化的装配bean
两种:
1,组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean
2,自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IOC/DI;
组件扫描和自动装配组合发挥巨大威力,使得显示的配置降到最少。
-》推荐不使用自动装配xml,而使用注解
autowire使用
1,首先在spring配置文件中引入context(上下文)
2,开启注解支持!
xmlns:context="http://www.springframework.org/schema/context"
<context:annotation-config/>
@Autowired
· @Autowired是按类型自动转配的,不支持id匹配
· 需要导入spring-aop的包!
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<bean id="person" class="com.zp.pojo.Person" autowire="byType" or autowire="byName">
<property name="name" value="zp"/>
1,byName
byName:会自动在容器上下文中查找和person,和自己对象set方法后面值相同的beanid!,id
缺点:byName:需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
2,byType
byType:会自动在容器上下文中查找和person,和自己对象属性类型相同的beanid!,class
缺点:byType:需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性类型一致
使用方法:
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
注意点:
如果定义了Autowired的require属性为false,说明这个对象可以为null,否则不允许为空,@Autowired(required = false)
public Person(@Nullable String name) {
this.name = name;
@Autowired(required = false)与@Nullable的效果一样
@Qualifier
· @Autowired是根据类型自动装配的,加上@Qualifier则可以根据bbyName的方式自动装配
· @Qualifier不能单独使用
@Resource
· @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
· 其次再进行,默认的byName方式进行装配;
· 如果以上都不成功,则按照byType的方式自动装配;
· 都不成功,则报异常。
@Resource(name = "cat2")
private Cat cat;
@Resource(name = "dog2")
private Dog dog;
private String name;
@Autowired与Q@Resource的区别
@Autowired和 @Resource的区别
* 1,都是用来自动装配的,都可以使用在字段上,(写在属性上或者set方法上)
Autowired(value="xxx")
REsource(name="xxx")
* 2,@Autowired通过byType实现,而且必须要求这个对象存在!【常用】
* 3, @Resource默认通过byName实现,如果找不到就使用byType实现,如果两个都没有实现,就报错,【常用】
* 4,执行顺序不同,@Autowired通过byType实现,@Resource默认通过byName实现
* */
4,使用注解开发
使用注解的前提准备:
1,导入AOP的jar包
直接导入:spring-webmvc的依赖,相当于导入所需的很多包。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
2,开启注解支持,和自动扫描
<!--指定要扫描的包,该包下的注解就会自动生效-->
<context:component-scan base-package="com.zp"/>
<!--开启注解支持-->
<context:annotation-config/>
1,bean
<bean id="user" class="com.zp.pojo.com.zp.pojo.User">
<property name="name" value="zp"/>
2,属性如何注入
//@Component,@Value("")是一套
//@Component等价于 <bean id="user" class="com.zp.pojo.User"/>
//@Value("zp") 相当于<property name="name" value="zp"/>
//@Component组件
@Component
public class User {
@Value("zp")
//相当于 <property name="name" value="zp"/>
public String name;
}
@Value("setname2")
public void setName2(String name2) {
this.name2 = name2;
}
注意点:首先会执行set方法上注入的值
3,衍生的注解
@Compoonent 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
、dao 【@Repository】
、service 【@Service】
、controller 【@Controller】
这四个注解的功能一样,都是代表将某个类注册到spring中,
装配Bean
4,自动装配置
-@Autowired:自动装配通过类型,名字
如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")
-@Nullale :字段标记了这个注解,说明这个字段可以为null;
-@Resouce:自动装配通过名字,类型
-@
5,作用域
package com.zp.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//@Component等价于 <bean id="user" class="com.zp.pojo.User"/>
//@Component组件
@Component
@Scope("singleton")
public class User {
@Value("zp")
//相当于 <property name="name" value="zp"/>
public String name;
}
6,小结
xml与注解
· xml更加万能,使用于任何场合!维护简单方便
· 注解不是自己的类使用不了,维护相对复杂!
xml 与注解最佳实践:
· xml 用来管理bean;
· 注解只负责完成属性的注入;
· 我们在使用的过程中,只需要注意一个问题:必须要让注解生效,就需要开启注解·的支持
<!--指定要扫描的包,该包下的注解就会自动生效-->
<context:component-scan base-package="com.zp"/>
<!--开启注解支持-->
<context:annotation-config/>
开启注解支持和·开启扫描的作用:
· 进行注解驱动注册,从而使注解生效
· 用于激活那些已经在spring容器中注册过的bean上的注解,也就是显式的向spring注册
· 如果不扫描包,就需要手动配置bean
· 如果不加注解驱动,则注入的值为null
9,使用java的方式配置spring
1,java类的配置方式
1,写在congig类中
**@Configration:**是一个配置类,和之前的beans.xml,applicationContext.xml一样
Configuration 修饰类,声明当前类是一个配置类,相当于applicationContext.xml文件
**@ComponentScan:**相当于<context:compent-scan base-package=“ ”>
于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的
**@Bean:**等于:@Component等价于
@Bean 修饰方法,该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。名称就是方法名bean.id
默认情况Spring会以方法名称作为对应bean定义的beanName。如果用户希望指定对应bean定义的beanName,则可以通过@Bean的name属性进行指定。
@Import 导入其他java配置类
属性: value[]:用于指定其他配置类的字节码。
使用: @Import({JdbcConfig.class})
也可以使用:注册多个配置类:context.register
2,写在实体类中
@component:
@Value();
3,小总结:
Component,组件,放在类上,说明这个类被spring管理了,就是bean
2,使用
在测试的时候要创建,new AnnotationConfigApplicationContext(UserConfig.class);
然后调用java类配置;
3,具体实现
@Configuration
class MyConfiguration {
@Bean
fun stringStore() = StringStore()
@Bean
fun integerStore() = IntegerStore()
}
@Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
@Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
实体类
package com.zp.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class User {
private String name;
public String getName() {
return name;
}
@Value("zp")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
配置文件
package com.zp.config;
import com.zp.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
//也会被spring容器托管,注册到容器中,因为他本来就是一个@Component,@Configration是一个配置类,和之前的beans.xml是一样的
@ComponentScan("com.zp.pojo")
public class zpConfig {
/*
* 注册一个bean,就像之前xml中的bean标签
* 这个方法的名字,就像bean标签中的id
* 这个方法的返回值,就像bean标签的class
* */
@Bean
public User getUser(){
return new User();
}
}
测试类
public class myTest {
@Test
public void Test(){
//如果使用了配置类的方式,只能使用AnnotationConfig上下文去获取容器,通过配置类的class对象来加载!
ApplicationContext context = new AnnotationConfigApplicationContext(zpConfig.class);
User user = context.getBean("getUser",User.class);
System.out.println(user.getName());
}
}
这种纯Java配置方式,在springboot中随处可见
10,代理模式
首先,AOP的底层机制就是动态代理
10.1,静态代理
什么是静态代理:
静态代理角色分析:
· 抽象对象:一般使用接口或者抽象类来实现
· 真实角色:被代理的角色
· 代理角色:代理真实角色:代理真实角色后,一般会有一些附属操作
· 客户:使用代理角色来进行一些操作
代理模式的好处:
代理模式的缺点:
10.2,加深理解
我们现在需要新增一个功能,
实现1:新增实现类
实现2:使用代理模式
10.3,动态代理
1,动态代理的思想
思想:我们在不改变原有代码的前提下,实现对原有功能的增强,这就是AOP中最重要的思想
AOP:
纵向开发,横向插入
动态代理:
· 动态代理和静态代理角色一样
· 动态代理的代理类是动态生成的,不是我们直接写好的!
· 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
· 基于接口的—JDK动态代理【我们在这里使用】
· 基于类:cglib
· java字节码实现:javasist
2重点:
需要了解两个类:
Proxy->代理,提供了创建动态代理类和实例的静态方法,他也是由这些方法创建的所有动态代理的超类
InvocationHandle->调用处理程序
具体理论:是由代理实例的调用处理程序实现的接口。每个代理实例都有一个关联的调用处理程序。
invoke()方法。
3,具体实现:
写在前面:JDK是动态生成代理类,并通过调用解析器,执行接口实现的方法的原理已经一目了然。动态代理加上反射,是很多框架的基础。比如Spring的AOP机制,自定义前置后置通知等控制策略,以及mybatis中的运用反射和动态代理来实现插件技术等等。
步骤:
首先:reflect.Proxy动态代理机制的主类,提供一组静态方法为一组接口动态的生成对象和代理类。
1,实现 :InvocatonHandler接口,重写方法invoke()
调用处理器接口,自定义invokle方法,用于实现对于真正委托类的代理访问。(调用处理程序或者叫调用处理器)
2,自定义方法 getProxt(),返回值为Object,在返回值中实现newProxyInstance();
newProxyInstance()方法:
该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
参数:
loader:类加载器来定义代理类
interfaces:代理类实现的接口列表
h:调度方法调用的调用处理函数(Invocationhandler类型)
3,最后在客户端类中调用处理程序
动态代理的好处(静态有的,没有的,它都有):
· 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
· 公共也就交给代理角色,实现了业务的分工
· 公共业务发生扩展时,方便集中管理!
· 一个动态代理类,代理的就是一个接口,一般对应的就是一类业务
核心:
· 一个动态代理类,可以代理多个类,只要是实现了同一个接口即可!
· 一个动态代理可以代理多个类,代理的就是接口
4,动态代理的实现机制:
1,通过实现 InvocationHandler 接口创建自己的调用处理器
2,通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类
3,通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;(代理接口)
4,通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
5,最后:通用的动态代理实现的类
思想:就是把所有代理对象设置为Object即可!
11,AOP
1,什么是aop
aop:(aspect Orientend Programming)意为:面向切面编程
2,Aop在spring中的作用
提供声明式事物:允许用户自定义切面
一下名词需要了解:
· 横切关注点:跨越应用想程序多个模块的方法或共功能。既是,与我们的业务逻辑无关,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等。。。。
· 切面(Aspect):横切关注点被模块化的特殊对象。即是,它是一个类。
· 通知(Advice):切面必须完成的工作。即,它是类中的一个方法。
· 目标(Target):被通知的对象。
**· 代理(Proxy):**向目标对象应用通知之后创建的对象。
***· 切入点(PointCut)😗**切面通知执行的“地点”的定义
**· 连接点(Join Point):**与切入点匹配的执行点。
springAop中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YzwAIkkI-1605087301321)(C:\Users\zp\Desktop\Spring学习文档/spring-advice.png)]
即Aop在不改变原有代码的情况下,去增加新的功能。
使用Spring实现Aop
【重点】使用AOP(织入),需要导入一个依赖包!
aspectj weaver.jar
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
第一种方式
通过Spring API实现(主要是SpringAPI接口实现)
首先编写我们的业务接口和实现类
package com.zp.dao;
public interface UserService {
public void add();
public void delete();
public void update();
public void select();
}
package com.zp.dao;
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("查询了一个用户!");
}
}
package com.zp.dao;
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("查询了一个用户!");
}
}
然后去写我们的增强类,我们编写两个,一个前置增强,一个后置增强
package com.zp.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class LogBefore implements MethodBeforeAdvice {
/*
* method:要执行的目标对象的方法
* args:参数
* target:要执行的目标
* */
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getClassLoader()+"的"+method.getName()+"被执行了!");
}
}
package com.zp.log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class LogAfter implements AfterReturningAdvice {
/*
* retuenvalue:返回值
* menthod:被调用的方法
* args:被调用的方法的对象的参数
* target:被调用的目标
* */
public void afterReturning(Object returnvalue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+target.getClass().getName()+"的"
+method.getName()+"方法"+"返回值"+returnvalue);
}
}
最后去spring的文件中注册,并实行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="userService" class="com.zp.dao.UserServiceImpl"/>
<bean id="logBefore" class="com.zp.log.LogBefore"/>
<bean id="logAfter" class="com.zp.log.LogAfter"/>
<!--<aop的配置-->
<aop:config>
<!--<切入点,expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.zp.dao.UserServiceImpl.*(..))"/>
<!--<执行环绕,advice-ref:执行方法,pointcut-ref:切入点-->
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/>
</aop:config>
</beans>
测试
import com.zp.dao.UserService;
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");
UserService userService = context.getBean("userService", UserService.class);
userService.delete();
}
}
Aop的重要性:很重要,一定要理解其中的思路,主要是思想的理解这一块。
Spring的Aop就是将公共的业务(日志,安全等)换让领域业务结合起来,就是当执行领域业务时,将会把公共业务加进来,实现公共业务的重复利用,领域业务更加纯粹,程序员专注领域业务,其本质还是动态代理。
第二种方式
方式二:自定义来实现AOP【主要是切面定义】
目标业务类不变,依旧是UserServiceImpl
注意点:实现过程的一些细节
1,在xml配置文件中先注册自定义(diy)的切面的Bean
2,配置aop 的代理
<aop:config></aop:config>
3,设置要使用的切面:定义切面类,
<aop:aspact ref="diy"></aop:aspact>
4,设置切入点
<aop:pointcut id="diypoint" expression="execution(* com.zp.service.UserServiceImpl.*(..))"/>
expression=“ ”
expression=“execution(* com.zp.service.UserServiceImpl.*(…))” :
” “ 里面就是用表达式的方式来定义切入点,只要是符合我们这个表达式要求的方法就是我们的连接点,连接点的集合就是我们要定义的切入点,
表达式中从左到右的*号
第一个* 表示方法的返回值类型不限
第二个* 表示包中的任意一个类
第三个 * 表示类中的任意一个方法
(…)表示方法中的所有参数
5,定义哪一个advice在哪一个切入点上面起作用
<aop:before method="logbefore" pointcut-ref="diypoint"/>
<aop:after method="logafter" pointcut-ref="diypoint"/>
before:表示会把切面类diy中的logbefore方法织入到名字叫做diypoint的切点上面
after:表示不管方法是否正常结束都会起作用
after-returning表示方法正常结束才会起作用(抛异常的时候不起作用)
配置通知 切面通知和切面绑定
pointcut:直接写表达式
pointcut-ref:指向表达式对象
pointcut与pointcut-ref:一般情况下只写一个
第一步:写我们自己的一个切入类
package com.zp.diy;
public class DiyPonit {
public void before(){
System.out.println("----------方法执行前-----------");
}
public void after(){
System.out.println("----------方法执行后-----------");
}
}
第二步:去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"
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="userService" class="com.zp.dao.UserServiceImpl"/>
<bean id="logBefore" class="com.zp.log.LogBefore"/>
<bean id="logAfter" class="com.zp.log.LogAfter"/>
<!--<aop的配置-->
<!--<第一种方式,使用spring Api ,接口实现-->
<!--<aop:config>
<!–<切入点,expression:表达式匹配要执行的方法–>
<aop:pointcut id="pointcut" expression="execution(* com.zp.dao.UserServiceImpl.*(..))"/>
<!–<执行环绕,advice-ref:执行方法,pointcut-ref:切入点–>
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="logAfter" pointcut-ref="pointcut"/>
</aop:config>-->
<!--第二种,使用自定义方式,主要是面向切面-->
<!--<首先注册bean-->
<bean id="diy" class="com.zp.diy.DiyPonit"/>
<!--<第二种,使用aop的标签实现-->
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diyPoint" expression="execution(* (com.zp.dao.UserServiceImpl).*(..))"/>
<aop:before method="before" pointcut-ref="diyPoint"/>
<aop:after method="after" pointcut-ref="diyPoint"/>
</aop:aspect>
</aop:config>
</beans>
第三步:测试
import com.zp.dao.UserService;
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");
UserService userService = context.getBean("userService", UserService.class);
userService.delete();
}
}
第三种方式
第三种方式:使用注解实现
第一步:编写一个注解实现的增强类
package com.zp.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.zp.dao.UserServiceImpl.*(..))")
public void before(){
System.out.println("-------------执行前!------------");
}
@After("execution(* com.zp.dao.UserServiceImpl.*(..))")
public void after(){
System.out.println("-------------执行后!------------");
}
@Around("execution(* com.zp.dao.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println("签名:"+jp.getSignature());
System.out.println(proceed);
}
}
第二步:在Spring配置文件种,注册Bean,并增加支持注解的配置
<!--<第三种方式:使用注解实现-->
<!--<首先,注册bean-->
<bean id="annotationPointcut" class="com.zp.diy.AnnotationPointcut"/>
<!--第二步:开启注解·-->
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy:说明
通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入(wear)切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
4,关于AOP使用java类配置去实现
步骤:
1,创建Config文件,
使用注解:
@Configuration
@ComponentScan(“ ”)
@Aspect
@EnableAspectJAutoProxy=><aop:aspectj-autoproxy/>
<!--第二步:开启注解·-->
2,在接口实现类里
@Component:实现Bean的注册
3,测试,
new AnnotationConfigApplicationContext
getBean:写bean为:实现类的bean,类型为接口
12,整合Mybatis
步骤:
1,导入相关jar包
· junit
· mybatis
· mysql数据库
· aop织入
· mybatis-spring【new】
2,编写配置文件
3,测试
12,1,回忆myBatis
12.2,Mybatis-spring
不想写
第一种方式
步骤:
1,编写数据源配置,
1.1;导入jar包
junit
lombok
mybatis-spring(重要)
spring-jdbc(spring使用数据库必备)
aspectJweaver
spring-webmvc
mybatis
mysql
1.2,编写配置文件:
· mybatis-config.xml:使用config
· spring-dao.xml:使用beans,同时还要写入AOP
配置数据源:dataSource
2,sqlSessionFactory
3,sqlSessionTEmplate
4,需要给接口加实现类【】
5,将自己写的实现类,注入到spring中(注册bean)
6,测试
第二种方式
步骤:
在原来的基础上:
1,新加实现类,继承SqlSessionDaoSuppose
2, 注册bean,mybatis-spring中的bean,和applicationContext中的bean
3,测试
13,事务管理机制
首先配置环境:导入所需的jar包
配置spring事务管理
声明式事务
步骤:
1,配置数据事务管理源(trnscationManager:DaraSourceTransactionManager)
2,结合aop实现事务的织入,
先是配置事务的通知;
再给方法配置事务:配置事务的传播特性:propagation:属性(一般情况下使用:REQUIRED)
3,最后配置事务的切入点
expression="execution(* com.zp.dao.*.*(..))",.*:dao下的所有类,.*所有方法,(..):所有参数
14,全部用注解或者java类配置实现
1,纯java配置
1,autowired
2,annotation
3,javaconfig
2,config,java类配置问题
报错信息:
1;Autowired annotation should only be used on methods with parameters
2020,11,9
pectj-autoproxy poxy-target-class=“true”/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
### 4,关于AOP使用java类配置去实现
步骤:
1,创建Config文件,
使用注解:
@Configuration
@ComponentScan(“ ”)
@Aspect
@EnableAspectJAutoProxy=><aop:aspectj-autoproxy/>
<!--第二步:开启注解·-->
2,在接口实现类里
@Component:实现Bean的注册
3,测试,
new AnnotationConfigApplicationContext
getBean:写bean为:实现类的bean,类型为接口
## 12,整合Mybatis
步骤:
1,导入相关jar包
· junit
· mybatis
· mysql数据库
· aop织入
· mybatis-spring【new】
2,编写配置文件
3,测试
### 12,1,回忆myBatis
### 12.2,Mybatis-spring
不想写
#### 第一种方式
步骤:
1,编写数据源配置,
1.1;导入jar包
junit
lombok
mybatis-spring(重要)
spring-jdbc(spring使用数据库必备)
aspectJweaver
spring-webmvc
mybatis
mysql
1.2,编写配置文件:
· mybatis-config.xml:使用config
· spring-dao.xml:使用beans,同时还要写入AOP
配置数据源:dataSource
2,sqlSessionFactory
3,sqlSessionTEmplate
4,需要给接口加实现类【】
5,将自己写的实现类,注入到spring中(注册bean)
6,测试
#### 第二种方式
步骤:
在原来的基础上:
1,新加实现类,继承SqlSessionDaoSuppose
2, 注册bean,mybatis-spring中的bean,和applicationContext中的bean
3,测试
## 13,事务管理机制
首先配置环境:导入所需的jar包
配置spring事务管理
**声明式事务**
步骤:
1,配置数据事务管理源(trnscationManager:DaraSourceTransactionManager)
2,结合aop实现事务的织入,
先是配置事务的通知;
再给方法配置事务:配置事务的传播特性:propagation:属性(一般情况下使用:REQUIRED)
3,最后配置事务的切入点
```xml
expression="execution(* com.zp.dao.*.*(..))",.*:dao下的所有类,.*所有方法,(..):所有参数
14,全部用注解或者java类配置实现
1,纯java配置
1,autowired
2,annotation
3,javaconfig
2,config,java类配置问题
报错信息:
1;Autowired annotation should only be used on methods with parameters
2020,11,9
物联网的项目