Spring的基本使用

Spring

Spring就是一个轻量级的控制反转(IOC) 和切面编程(AOP)的框架

IOC的核心是工厂模式,AOP的核心是代理模式

IOC理论推导

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码,如果程序代码量十分大,那么修改一次的成本代价十分昂贵

控制反转

使用一个Set接口实现.已经发生了巨大的变化:

private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

之前,程序是主动创建对象,控制权在遍好的程序本身

使用了set注入后,程序不在具有主动性,而是变成了被动的接受对象

这种思想,从本质上解决了问题,程序不用去管理对象的创建了,系统的耦合性大大降低,可以更加专心的在业务上的实现,这是IOC的原型

IOC本质:

控制反转,对象的创建由程序自己控制,控制反转之后将对象的创建交由第三方,获取依赖对象的方式反转了

依赖注入和控制反转(IOC)

一个Java应用程序,对象间往往是相互依赖的。

Spring框架的控制反转(Inversion of Control)就是为了解决这个问题的。

配置第一个Spring

1.导入依赖
<!-- 导入依赖 -->
<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
		<!--spring-webmvc模块(也被称作Web-Servlet模块)包含Spring MVC框架。-->
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>
2.配置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">
    <!--  使用Spring来创建对象,在Spring这些都称为Bean  -->
    <!--
        bean等于对象,id为变量名,class为对象路径
        property相当于给对象中的属性设一个值
      -->
    <bean id="hello" class="com.spring.pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>
</beans>
3.测试类
public class MyTest {
    public static void main(String[] args) {
        //获取Spring上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就行
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.getStr());
    }
}

配置初型IOC Spring

实体类:
public class MySqlDaoImpl implements UserDao {
    public void show() {
        System.out.println("这里是Mysql");
    }
}
public class UserDaoImpl implements UserDao {
    public void show() {
        System.out.println("这里是User");
    }
}
接口:
public interface UserService {
    void getUserDao();
}
public interface UserDao {
    void show();
}
服务层:
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUserDao() {
        userDao.show();
    }
}
配置文件:
<?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  -->
    <!--
        bean等于对象,id为变量名,class为对象路径
        property相当于给对象中的属性设一个值
    -->
    <bean id="MySqlImpl" class="com.spring.dao.MySqlDaoImpl"/>
    <bean id="UserImpl" class="com.spring.dao.UserDaoImpl"/>
    <bean id="service" class="com.spring.service.UserServiceImpl">
        <!--  ref引入Spring容器创建好的对象(bean)  -->
        <property name="userDao" ref="MySqlImpl"/>
    </bean>
</beans>
测试类
//获取Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就行
UserServiceImpl service = (UserServiceImpl) context.getBean("service");
service.getUserDao();
小结:

1.我们将建好的对象在Spring容器中使用bean重新创建

<bean id="MySqlImpl" class="com.spring.dao.MySqlDaoImpl"/>

2.我们在服务层IOC写入

private UserDao userDao;
//这里起到的作用就是将传递过来的对象赋值给userDao
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}
//类似于控制反转,我们就可以调用传递过来的对象来调用方法
public void getUserDao() {
    userDao.show();
}

3.测试类来调配

//获取Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中的管理了,我们要使用,直接去里面取出来就行
//参数为配置文件bean标签的id
UserServiceImpl service = (UserServiceImpl) context.getBean("service");
service.getUserDao();

4.这样子我们修改调用的对象只需要在配置文件中更改ref的引入即可

<bean id="service" class="com.spring.service.UserServiceImpl">
    <!--  ref引入Spring容器创建好的对象(bean)  -->
    <property name="userDao" ref="MySqlImpl"/>
</bean>

IOC创建对象的方式

1.使用无参构造创建对象(默认创建方式)

<bean id="user" class="com.spring.pojo.User"/>

2.假设我们要使用有参构造创建对象

2.1,下标赋值:

<bean id="user" class="com.spring.pojo.User">
    <!-- index代表构造方法参数下标(从0开始) value为传递的值 -->
    <constructor-arg index="0" value="参数值"/>
</bean>

2.2,参数赋值

<bean id="user" class="com.spring.pojo.User">
    <constructor-arg type="java.lang.String" value="类型值"/>
</bean>

2.3,参数名赋值:

<bean id="user_value" class="com.spring.pojo.User">
    <constructor-arg name="name" value="参数名"/>
</bean>
总结:

实体类:

public class User {
    private String name;

    public User() {
        this.name = "无参构造";
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

配置文件:

<!--  构造方法创建对象(默认)  -->
<bean id="user" class="com.spring.pojo.User"/>

<!--  有参构造创建对象(通过下标)  -->
<bean id="user_index" class="com.spring.pojo.User">
    <constructor-arg index="0" value="构造方法参数值"/>
</bean>

<!--  类型传值创建对象(引用类型用全类名)  -->
<bean id="user_type" class="com.spring.pojo.User">
    <constructor-arg type="java.lang.String" value="类型参数值"/>
</bean>

<!--  参数名创建对象(对应属性名赋值即可)  -->
<bean id="user_value" class="com.spring.pojo.User">
    <constructor-arg name="name" value="参数名"/>
</bean>

测试类:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User bean = (User) context.getBean("user");
User bean_index = (User) context.getBean("user_index");
User bean_type = (User) context.getBean("user_type");
User bean_value = (User) context.getBean("user_value");
System.out.println("无参构造方法:"+bean.getName());
System.out.println("有参构造方法:"+bean_index.getName());
System.out.println("类型创建对象:"+bean_type.getName());
System.out.println("参数名赋值法:"+bean_value.getName());

运行结果:

无参构造方法:无参构造
有参构造方法:构造方法参数值
类型创建对象:类型参数值
参数名赋值法:参数名

结论:在配置文件加载的时候,容器中管理的对象就已经初始化了

Spring配置

别名:在调用时既可以用别名,也可以用原名
<!--  别名,左边对应老bean id 右边对应新别名  -->
<alias name="user_index" alias="index"/>
User bean_index = (User) context.getBean("user_index");
User index = (User) context.getBean("index");
System.out.println("别名下标创建:"+index.getName());
System.out.println("有参构造方法:"+bean_index.getName());

运行结果:
别名下标创建:构造方法参数值
有参构造方法:构造方法参数值
bean:
<!-- id:唯一标识,相当于我们创建的对象名 | class为全限定名 :包名+类名 | name:也是别名,而且可以取多个 -->
<bean id="name" class="com.spring.pojo.User" name="n1,n2">
<!-- name属性可以通过","取多个别名用空格同理,使用";"也可以 -->
</bean>
improt:

一般用于团队开发使用,可以将多个配置文件导入合并为一个

applicationContext.xml

<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

依赖注入:

构造器注入
<!--  构造方法创建对象(默认)  -->
<bean id="user" class="com.spring.pojo.User"/>

<!--  有参构造创建对象(通过下标)  -->
<bean id="user_index" class="com.spring.pojo.User">
    <constructor-arg index="0" value="构造方法参数值"/>
</bean>

<!--  类型传值创建对象(引用类型用全类名)  -->
<bean id="user_type" class="com.spring.pojo.User">
    <constructor-arg type="java.lang.String" value="类型参数值"/>
</bean>

<!--  参数名创建对象(对应属性名赋值即可)  -->
<bean id="user_value" class="com.spring.pojo.User">
    <constructor-arg name="name" value="参数名"/>
</bean>

Set方式注入 [重点]

依赖注入:Set注入!

​ 依赖:bean对象的创建依赖于容器

​ 注入:bean对象中的所有属性由容器来注入

【环境搭配】

实体类:

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 Properties info;
    private String wife;
}

配置文件:

<bean id="address" class="com.spring.pojo.Address">
    <property name="address" value="地址"/>
</bean>

<bean id="student" class="com.spring.pojo.Student">
    <!--  1:  普通注入    -->
    <property name="name" value="乱杀!"/>
    <!--  2: Bean注入 ref    -->
    <property name="address" ref="address"/>
    <!--  3: 数组注入   -->
    <property name="books">
        <array>
            <value>数组</value>
            <value>对象数组</value>
            <value>二维数组</value>
        </array>
    </property>
    <!--  4: List注入  -->
    <property name="hobbys">
        <list>
            <value>list</value>
        </list>
    </property>
    <!--  5: Map注入  -->
    <property name="card">
        <map>
            <entry key="" value=""/>
        </map>
    </property>
    <!-- 6:Set注入 -->
    <property name="games">
        <set>
            <value>Set</value>
        </set>
    </property>
    <!-- 8:空值注入 -->
    <property name="wife">
        <null/>
    </property>
    <!-- 9:Properties注入 -->
    <property name="info">
        <props>
            <prop key=""></prop>
        </props>
    </property>
</bean>

测试类:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Student student = (Student) context.getBean("student");
System.out.println("属性:"+student.getName());
System.out.println("对象:"+student.getAddress().getAddress());
System.out.println("数组:"+student.getBooks()[1]);
System.out.println("list:"+student.getHobbys().toString());
System.out.println("map:"+student.getCard().toString());
System.out.println("set:"+student.getGames().toString());
System.out.println("Properties:"+student.getInfo().toString());
System.out.println("空值:"+student.getWife());

运行结果

属性:乱杀!
对象:地址
数组:对象数组
list:[list]
map:{=}
set:[Set]
Properties:{=}
空值:null

拓展方式注入
【P命名空间注入】

P约束引入:

xmlns:p = "http://www.springframework.org/schema/p"

使用方式:

<!--  P命名空间注入,可以直接注入属性值  -->
<bean id="user" class="com.spring.pojo.User" p:name="张三" p:age="18" />
【C命名空间注入】

C约束引入:

xmlns:c = "http://www.springframework.org/schema/c"
<!--  C命名空间注入 构造器注入:construct-args -->
<!-- c:_0代表下标,也可以直接:属性名来注入 -->
<bean id="user_2" class="com.spring.pojo.User" c:_0="" c:_1=""/>

注意点:P和C命名空间不可以直接使用,需要引入xmlns约束

bean作用域

1.单例模式(Spring默认机制)

<bean id="user_2" class="com.spring.pojo.User" c:_0="" c:_1="" scope="singleton"/>

2.原型模式:每次从容器中get的时候,都会产生一个新对象

<bean id="user_2" class="com.spring.pojo.User" c:_0="" c:_1="" scope="prototype"/>

3.其余的 request,session,application,这些个只能在web开发中使用到

Bean的自动装配

自动装配是Spring满足bean依赖的一种方式

Spring会在上下文中自动寻找,并自动给bean装配属性

在Spring中有三种装配的方式:

1.在xml中显示的配置

2.在java中显示的配置

3.隐式的自动装配bean【重要】

自动装配(autowire)
byName
<!--  自动装配  -->
<bean id="people_self" class="com.spring.pojo.People" autowire="byName">
    <property name="name" value="byName自动装配"/>
</bean>

autowire:byName元素会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid

ByType
<!--  自动装配  -->
<bean id="people_self" class="com.spring.pojo.People" autowire="byType">
    <property name="name" value="byType自动装配"/>
</bean>

autowire:byType元素会自动在容器上下文中查找和自己对象属性相同的beanid(弊端:保证这个bean类型全局唯一,优点:可以省略id命名)

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!

  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

使用注解实现自动装配

要使用注解须知:

1.导入约束 context约束

2.配置注解的支持:context:annotation-config/

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">
 
    <!--  开启注解支持  -->
    <context:annotation-config/>
</beans>
@Autowired

加在对象属性上即可,也可以在set方式上使用

使用@Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName

@Autowired:

  • 当注入在IOC容器中该类型只有一个时,就通过byType进行装配
  • 当注入容器存在同一个类型的对象时,就根据byName进行装配
@Autowired
private Cat cat;
@Autowired
@Qualifier (value = "dog")
private Dog dog;
private String name;

@Qualifier自动装配的环境比较复杂,自动装配无法通过一个注解完成的时候,我们可以使用@Qualifier( value = “xxx”)去配和@Autowired的使用,指定一个唯一的bean对象注入

@Resource
@Resource (name = "cat")
private Cat cat;

@Resource
private Dog dog;
private String name;

小结:

@Resource和@Autowired的区别

  • 都是用来自动装配的,都可以放在这段上
  • @Autowired 通过byType的方式实现 【常用】
  • @Resource 默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!
  • 执行顺序不同:@Autowired 通过byType的方式实现。@Resource 默认通过byName的方式实现。

使用注解开发

1.bean
  • 1.1:开启注解支持,引入扫描包

  • <!--  开启注解支持  -->
    <!--  创建对象 指定要扫描的包,这个包下的注解会生效  -->
    <context:component-scan base-package="com.spring.pojo"/>
    
  • 1.2:在扫描包下的类上加上注解:@Component 即可

  • @Component  //等价于在容器中注册了一个bean <bean id="user" class="com.spring.pojo.User">
    public class User {}
    
2.属性如何注入
  • @Value("张三")  //等价于:<property name="name" value="张三"/>
    private String name;
    
3.衍生的注解

@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层

  • dao 【@Repository】
  • service【@Service】
  • controller(Servlet)【@Controller】
  • 这四个注解都是一样的,都是代表将某个类注册到Spring,装配Bean
4.自动装配配置

@Autowired

@Autowired
private Cat cat;
@Autowired
@Qualifier (value = "dog")
private Dog dog;
private String name;

@Resource

@Resource (name = "cat")
private Cat cat;
@Resource
private Dog dog;
private String name;
5.作用域
@Scope("prototype") //单例模式:singleton  原型模式:prototype
public class User {}
6.小结

xml与注解

  • xml更加万能,适用于各种场合,维护简单方便
  • 注解不是自己的类无法使用,维护相对复杂

最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入
  • 我们在使用的过程,只需要注意一个问题,必须让注解生效,就需要开启注解的支持

使用Java的方式配置Spring(新特性)

  • 我们现在要完全不使用Spring的xml配置了,全权交给Java来做

  • JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能

配置类(config 相当于Spring的applicationContext.xml容器):

@Configuration  //这个也会被Spring容器托管,注册在容器中,因为他本身就是一个@Component 代表这是一个配置类,就和我们之前看到的Spring的applicationContext.xml一样
@ComponentScan("com.spring.pojo")//扫描pojo实体类包
public class HonMaoConfig {
    /**
     * 注册一个bean,就相当于我们在Spring容器中写入一个bean标签
     * 这个方法的名字,就相当于bean标签的id属性
     * 这个方法的返回值,就相当于bean标签的id属性
     */
    @Bean
    public User getUser(){
        return new User();//就是返回要注入到bean的对象
    }
}

实体类:

@Component	//等价于在容器中注册了一个bean <bean id="user" class="com.spring.pojo.User">
public class User {
    @Value("HonMao") //给name属性赋值
    private String name;
}

测试类(AnnotationConfigApplicationContext):

public class MyTest {
    @Test
    public void getConfig(){
		/**如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig上下文来获取容器
           通过配置类的class对象加载*/
        ApplicationContext context = new AnnotationConfigApplicationContext(HonMaoConfig.class);
        User getUser = context.getBean("getUser", User.class);//加载
        System.out.println(getUser.getName());
    }
}

这种纯Java的配置方式,在SpringBoot随处可见

代理模式

为什么学习静态代理模式?因为这是SpringAOP的底层!【SpringAOP 和 SpringMVC】

代理的分类:

静态代理

静态代理,代理相当于一个枢纽,举例,我们在生活中去看电影,首先我们需要到电影院或者视频APP,而电影院和视频APP就在看电影这个流程中扮演者代理的角色,首先是剧组将电影拍摄完成再发布给电影院和APP,而我们并不是直接通过剧组去看电影,而是通过第三方(代理),电影院(视频APP),虽然不是通过剧组直接看电影,但看电影的目的同样达到了。

而我们如何在代码中实现,例如写一个中介租房:

影片胶卷接口:

//影片胶卷
public interface ShePian {
    void shoot();
}

剧组实现胶卷接口:

//剧组
public class JuZu implements ShePian{
    public void shoot() {
        System.out.println("唐人街电影开始播放!");
    }
}

电影院类:

//电影院
public class DianYingYuan {
    private JuZu juzu;
    //日志文件
    public DianYingYuan(JuZu juzu) {
         log("唐人街");
        this.juzu = juzu;
    }

    public JuZu getJuzu() {
        return juzu;
    }

    public void log(String msg){//电影院添加的功能
        System.out.println("荧幕开始放映:"+msg+"预告片");
    }
    
}

观众:

//观众
public class GuanZho {
    public static void main(String[] args) {
        DianYingYuan ying = new DianYingYuan(new JuZu());//告诉电影院要看什么电影
        ying.getJuzu().shoot();//开始放映
    }
}

运行结果:

荧幕开始放映:唐人街预告片
唐人街电影开始播放!

这就是静态代理,观众的目的是为了看电影,而电影的原头在剧组,虽然借助了电影院,但目的并没有发生差异,甚至电影院还有其他功能帮助观众提升影视质量,例如上述的播放预告片

代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公众的业务
  • 公共也就交给代理角色!实现了业务分工
  • 公共业务发展拓展的时候,方便集中管理

代理的缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低
动态代理★
  • 动态代理和静态代理角色一样
  • 动态代理的代理是动态类的,不是我们直接写的
  • 基于代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口—JDK动态代理【我们使用的】
    • 基于类:cglib
    • java字节码实现:javasist

需要了解两个类:Proxy,InvocationHandler:调用处理程序

代理的概念:你只需要将需要处理的数据给到动态代理,代理帮你完成各项工作,最终反馈给你想要的成品,例如一条sql语句,丢入到代理当中,你只需要告诉代理你需要执行的sql操作和表明即可,剩下的执行sql语句通过代理帮你完成

AOP

1.导入依赖包:

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
</dependencies>

方式一:使用原生Spring API接口

接口:

public interface UserService {
    void add();
}

实现接口:

public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("增加用户");
    }
}

切面代码:

public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为"+returnValue);
    }
}
public class Log implements MethodBeforeAdvice {
    //method:要执行的目标对象的方法
    //objects :参数
    //o :目标对象
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        //对象的xxx方法被执行了
        System.out.println(o.getClass().getName()+"的"+method.getName());
    }
}

配置文件:

<!--  注册bean  -->
<bean id="UserService" class="com.spring.service.UserServiceImpl"/>
<bean id="log" class="com.spring.log.Log"/>
<bean id="afterLog" class="com.spring.log.AfterLog"/>

<!--  方式一:使用原生Spring API接口  -->
<!--  配置aop:需要导入aop的约束  -->
<aop:config>
<!--   切入点:   expression:表达式 execution(要执行的位置)  -->
    <aop:pointcut id="pointcut" expression="execution(* com.spring.service.UserServiceImpl.*(..))"/>
    <!--    执行环绕增加    -->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>

代理代码:

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理 代理的是接口
        UserService userService = (UserService) context.getBean("UserService");
        userService.add();
    }
}

Cart+p 查找文件 +n新建文件 +o打开文件夹 +u插入表格 +w关闭

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值