四、bean的作用域设置
spring中的bean现在一共有如下作用域,其中只有prototype不为单例模式,其余的均为单例模式。在默认情况下的作用域为singleton
<?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:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="person" scope="prototype" class="com.zhou.spring.test_001.Person"> </bean> <bean id="food" class="com.zhou.spring.test_001.Food"> <constructor-arg name="name" value="Lucy"></constructor-arg> <constructor-arg name="age" value="30"></constructor-arg> </bean> </beans>
在applicationContext1.xml中设置bean的作用域,scope=“prototype”,那么在主程序中打印的new出来的对象均为同一个。
package com.zhou.spring.test_001; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author zhouyanxiang * @create 2020-07-2020/7/11-18:20 * 当bean的scope为prototype的时候为非单例模式,即new的对象都不是同一个 */ public class SpringStart { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext1.xml"); Person person = (Person) ctx.getBean("person"); Person person2 = (Person) ctx.getBean("person"); Person person3 = (Person) ctx.getBean("person"); System.out.println(person.toString()); System.out.println(person2.toString()); System.out.println(person3.toString()); } }
打印的结果会是三个的toString()均不一样
当然在默认情况下,不设置scope的范围,参考applicationContext2.xml设置,那么打印的结果会是同一样的。
五、工厂模式
得了解一下工厂模式的优点:
首先,工厂模式是为了解耦:把对象的创建和使用的过程分开。就是Class A 想调用 Class B ,那么A只是调用B的方法,而至于B的实例化,就交给工厂类。
其次,工厂模式可以降低代码重复。如果创建对象B的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。我们可以这些创建对象B的代码放到工厂里统一管理。既减少了重复代码,也方便以后对B的创建过程的修改维护。
由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建B的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。同理,想把所有调用B的地方改成B的子类B1,只需要在对应生产B的工厂中或者工厂的方法中修改其生产的对象为B1即可,而不需要找到所有的new B()改为new B1()。
另外,因为工厂管理了对象的创建逻辑,使用者并不需要知道具体的创建过程,只管使用即可,减少了使用者因为创建逻辑导致的错误。
这个是我创建的一个模拟的来理解工厂模式的类图
有一个接口Car,里面有两个方法
有两个具体的类实现了Car接口,分别是BWM和Audi。
创建一个CarFactory,来构造返回一个Car类型的getCar()。CarFactory的具体代码如下:
package com.zhou.spring.test_001; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-16:09 */ public class CarFactory { public CarFactory(){ super(); System.out.println("car factory"); } public static Car getCar(String name) throws Exception { if (name.equals("Audi")){ return new Audi(); }else if (name.equals("BWM")){ return new BWM(); }else { throw new Exception(); } } }
来判断传入的参数的name是否是其实现类的一个,如果是则返回一个新的实现类的对象,否则就抛出异常。
在StartSpring里面来主函数来输出
package com.zhou.spring.test_001; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-16:15 */ public class StartSpring { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); Car car = ctx.getBean("car",Car.class); System.out.println("name: " + car.getName() + "\t" + "price: " + car.getPrice()); } }
applicationContext.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"> <bean id="car" class="com.zhou.spring.test_001.CarFactory" factory-method="getCar" > <constructor-arg value="Audi"></constructor-arg> </bean> </beans>
就构造了一个简单的id为Car的bean。利用依赖注入给CarFactory里面的getCar注入了一个“Audi”的参数,
然后就可以体验工厂模式带来的效果。
最后输出结果如下:
六、循环引用
通常来讲就是在A类中的成员变量含有对B类的引用,B类的成员变量含有对C类的引用,C类的引用中含有对A类的引用,这样三个就产生了循环引用。如下所示,分别是A、B、C三个类
package com.zhou.spring.test_003; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-18:01 */ public class A { private B b; public B getB() { return b; } public void setB(B b) { this.b = b; } }
package com.zhou.spring.test_003; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-18:01 */ public class B { private C c; public C getC() { return c; } public void setC(C c) { this.c = c; } }
package com.zhou.spring.test_003; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-18:01 */ public class C { private A a; public A getA() { return a; } public void setA(A a) { this.a = a; } }
配置文件applicationContext3.xml,在这个里面是不能同时设置三个bean的作用域为scope=“prototype”,否则就会报错。
<?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:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--初始化顺序跟配置文件的配置bean的顺序有关--> <!--<value></value> 和 <null></null>里面内容都为空的时候,前者的属性得到的是"",后者得到的是null--> <!--autowire="byType" 按照类型来的时候是看引用的类型名 --> <!--autowire="byName" 按照名字来的时候是看引用的变量名--> <bean id="b" class="com.zhou.spring.test_003.B" > </bean> <bean id="C" class="com.zhou.spring.test_003.C" autowire="byType"> </bean> <bean id="A" class="com.zhou.spring.test_003.A" autowire="byName"> </bean> </beans>
主函数的类
package com.zhou.spring.test_003; import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-18:02 */ public class SpringTest { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext3.xml"); A a = ctx.getBean("A",A.class); System.out.println(a.getB()); C c = ctx.getBean("C",C.class); System.out.println(c.getA()); } }
七、注解
首先了解一下mvc的三层架构理念:通过三层架构可以很好的解耦合
- Model层:负责具体的细节处理实现功能和数据交互
- Dao层:负责与数据库打交道
- Service层:负责具体的细节逻辑实现
- View层:负责视图的展示
- Controller层:负责逻辑控制
下面是整个MVC架构和单例的讲解图
那么为了能够相当于有bean,需要在controller上添加@component注解,在service上也需要加上,然后这样在主函数类里面就能够发现注册的bean,但是为了区别,所以有了@Controller和@Service分别代表了controller层的注入bean和service层的注入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" xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扫描指定包下的 带有Component标签的类,纳入spring管理 --> <context:component-scan base-package="com.zhou.spring"></context:component-scan> </beans>
- controller层
package com.zhou.spring.controller; import com.zhou.spring.entity.User; import com.zhou.spring.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-20:57 * controller 层是在web最开始先接入的,控制整体逻辑转发部分 */ @Controller("UserController2") public class UserController { /*默认的是byType*/ @Autowired UserService userService; public String list(){ String username = "Tom"; String password = "123456"; User user = userService.login(username, password); if (user == null){ return "failed"; }else { return "success"; } } }
- Dao层
UserDao
package com.zhou.spring.dao; import org.springframework.stereotype.Repository; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-21:12 * dao层负责和数据库打交道的,数据逻辑层 */ @Repository public interface UserDao { public String getName(String name); }
UserDaoImpl
package com.zhou.spring.dao.impl; import com.zhou.spring.dao.UserDao; import org.springframework.stereotype.Component; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-21:46 */ @Component public class UserDaoImpl implements UserDao { @Override public String getName(String name) { System.out.println("name:" + name + "正在查找过程中"); return name; } }
- entity层
package com.zhou.spring.entity; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-20:56 * entity层一般为直接建立的简单实体类,pojo类 */ public class User { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User(String username, String password) { this.username = username; this.password = password; } }
- Service
package com.zhou.spring.service; import com.zhou.spring.dao.UserDao; import com.zhou.spring.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-20:56 * Service层负责具体的细节逻辑处理 */ @Service("UserService") public class UserService { @Autowired UserDao userDao; public User login(String username, String password){ System.out.println("username: " + username); System.out.println("Service "); System.out.println(userDao.getName(username)); return new User(username,password); } }
最后调用实现
package com.zhou.spring; import com.zhou.spring.controller.UserController; import com.zhou.spring.service.UserService; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author zhouyanxiang * @create 2020-07-2020/7/13-21:05 */ public class TestBean { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); UserController userController = ctx.getBean("UserController2", UserController.class); System.out.println(userController.toString()); System.out.println(userController.list()); } }
最后输出结果