JAVA spring框架学习笔记(二)
javabean的lazy_init属性为什么默认设置为false,即为什么bean默认是不使用懒加载的。原因有两个:
- 使用懒加载,在使用这个bean对象时才会发现问题,无法提前知道存在的问题,容易有隐患。不使用懒加载可提前发现配置问题。
- 在使用时才去加载它,会导致使用速度变慢,影响相应时间。不使用懒加载,bean对象存放在缓存中,使用时不用去实例化它,加快运行效率。
spring项目分层:
一般可分为Dao层、Service层和Controller层。
Dao层主要和数据库相关联,执行数据库中的增删改查操作。
Service层建立在Dao层之上,利用Dao层传上来的数据进行进一步的服务操作。
Controller层主要关联页面和Service层,将页面的请求传到Service层,然后service层操作完之后将结果传到页面。
以一个简单的用户登录为例:
Dao层主要实现用户传入一个账号和密码之后从数据库中查询对应的账号以及该账号对应的密码,将正确的账号和密码传到Service层。
Service层核对正确的账号和密码与用户输入的是否一致,并向controller层返回核对结果。controller层将核对结果传到页面。
代码实现:
// Dao层
package com.login.dao;
import com.login.po.User;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
// 设置姓名和密码
private final String USERNAME = "admin";
private final String USERPWD = "123456";
public User querryUserByName(String userName) {
// 判断用户名是否存在
if (!USERNAME.equals(userName))
return null;
User user = new User();
user.setUserName(userName);
user.setUserPwd(USERPWD);
user.setUserId(1);
return user;
}
}
// Service层
package com.login.service;
import javax.annotation.Resource;
import com.login.dao.UserDao;
import com.login.po.User;
import com.login.vo.MessageModel;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// 注入
@Resource
private UserDao userDao;
public MessageModel userLogin(String userName, String userPwd) {
MessageModel messageModel = new MessageModel();
// 参数的非空校验
if (userName == null || "".equals(userName.trim())) { // trim 去除userName中前缀或者后缀的空格
messageModel.setCode(0);
messageModel.setMsg("用户名不能为空");
return messageModel;
}
if (userPwd == null || "".equals(userPwd.trim())) {
messageModel.setCode(0);
messageModel.setMsg("密码不能为空");
return messageModel;
}
// 调用Dao层的查询方法判断用户对象是否存在
User user = userDao.querryUserByName(userName);
if (user == null) {
messageModel.setCode(0);
messageModel.setMsg("用户对象不存在");
return messageModel;
}
// 比较密码是否正确
if (!user.getUserPwd().equals(userPwd)){
messageModel.setCode(0);
messageModel.setMsg("用户密码错误");
return messageModel;
}
messageModel.setCode(1);
messageModel.setMsg("SUCCESS");
return messageModel;
}
}
// 用户类
package com.login.po;
public class User {
private Integer userId;
private String userName;
private String userPwd;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
}
// 消息类
package com.login.vo;
import java.security.cert.PKIXCertPathValidatorResult;
/**
* 封装相应对象
*/
public class MessageModel {
private Integer code; // 状态码 0:失败 1:成功
private String msg; // 提示信息
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
@Override
public String toString() {
return "MessageModel [code=" + code + ", msg=" + msg + "]";
}
}
// 登录测试
package com.login;
import com.login.controller.UserController;
import com.login.vo.MessageModel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.support.ClassPathXmlApplicationContext;
// @SpringBootApplication
public class LoginApplication {
public static void main(String[] args) {
ClassPathXmlApplicationContext cp = new ClassPathXmlApplicationContext("spring.xml");
UserController userController = (UserController) cp.getBean("userController");
MessageModel messageModel = userController .userLogin("admin", "123456");
System.out.println(messageModel);
}
}
xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
第三行加了
xmlns:context="http://www.springframework.org/schema/context"
在xsi:schemaLocation中要加入规范文件
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
-->
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启自动扫描,并设置扫描包范围,采用自动扫描这一行不能忘-->
<context:component-scan base-package="com.login"/>
</beans>
bean作用域:
1. 单例作用域:singleton(默认)。bean被实例化后会放在到单例缓存池中,每次获取的都是同一个bean对象。
2. 原型作用域:prototype。bean每次被实例化都会创建一个新的bean对象。
bean作用域的设置可用scope属性。
web中的作用域:
request作用域:每次请求都创建一个新的bean对象。
session作用域:每次会话都创建一个新的bean对象。
bean的生命周期:
创建
初始化:xml中指定init-method或者重写init接口
使用:getbean
销毁:xml中指定destroy-method,并使用close关闭容器。
AOP中的代理:
代理三要素:
- 有共同的行为接口
- 目标角色实现行为
- 代理角色实现行为,增强目标对象行为
静态代理
静态代理一般将共同的行为定义为一个接口形式,目标角色和代理角色重写接口函数,并在代理角色中设置一个接口对象来接一个具体的目标角色,并通过这个目标角色的行为函数来实现静态代理中的行为函数,另外静态代理也可在目标角色的行为函数的基础上扩展一下字节的行为。
特点:
- 目标角色固定
- 代理对象会增强目标对象的行为
- 有可能存在多个代理,引起”类爆炸”
代码实现
// 租房行为接口
package com.static_agent;
public interface RentHouse {
public void toRentHouse();
}
// 结婚行为接口
package com.static_agent;
public interface Marry {
public void toMarry();
}
// 目标角色实现结婚和租房接口
package com.static_agent;
public class User implements RentHouse, Marry{
@Override
public void toRentHouse() {
// TODO Auto-generated method stub
System.out.println("我要租一个三室一厅的房间...");
}
@Override
public void toMarry() {
// TODO Auto-generated method stub
System.out.println("我要结婚了...");
}
}
// 租房代理实现租房接口
package com.static_agent;
public class HouseAgency implements RentHouse{
// 获取目标角色
private RentHouse target;
// 采用有参构造来初始化目标角色
public HouseAgency(RentHouse target) {
this.target = target;
}
@Override
public void toRentHouse() {
// TODO Auto-generated method stub
System.out.println("我可以帮忙租房...");
// 调用目标角色中的行为函数
target.toRentHouse();
// 代理角色的行为扩展
System.out.println("马上准备合同");
}
}
// main函数做测试
package com.static_agent;
public class Starter1 {
public static void main(String[] args) {
RentHouse target = new User();
HouseAgency houseAgency = new HouseAgency(target);
houseAgency.toRentHouse();
Marry marry = new User();
MarryCompany marryCompany = new MarryCompany(marry);
marryCompany.toMarry();
}
}
动态代理:JDK动态代理和CGLIB动态代理
JDK动态代理: 要求目标对象有接口实现。
JDK动态代理的大体原理类似于模板类,提供了一个目标对象就能生成一个对应的代理对象。具体实现就是实现了一个JDKProxy类,其中实现了利用Spring的Proxy.newProxyInstance方法实现了getProxy函数用以返回一个目标对象对应的代理对象。
package com.dymatic;
public interface RentHouse {
public void toRentHouse();
}
package com.dymatic;
public interface Marry {
public void toMarry();
public String toMarry2();
}
package com.dymatic;
public class User implements RentHouse, Marry {
@Override
public void toRentHouse() {
// TODO Auto-generated method stub
System.out.println("我要租房...");
}
@Override
public void toMarry() {
// TODO Auto-generated method stub
System.out.println("我要结婚...");
}
@Override
public String toMarry2() {
// TODO Auto-generated method stub
return "二婚";
}
}
package com.dymatic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.aopalliance.intercept.Invocation;
public class JDKProxy {
private Object target;
public JDKProxy(Object target) {
this.target = target;
}
public Object getProxy() {
ClassLoader loader = this.getClass().getClassLoader();
Class[] interfaces = target.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
// System.out.println("invoke...");
Object object = method.invoke(target, args);
return object;
}
};
// Proxy.newProxyInstance需要有三个参数:类加载器、目标对象接口的实现数组、以及一个invocation接口
Object proxy = Proxy.newProxyInstance(loader, interfaces, invocationHandler);
return proxy;
}
}
package com.dymatic;
public class Starter {
public static void main(String[] args) {
// 设置目标对象用来初始化代理类
RentHouse rentHouse_Target = new User();
// 获取代理类
JDKProxy rentHouse_jdkProxy = new JDKProxy(rentHouse_Target);
// 调用代理类中的方法,获取代理对象
RentHouse rentHouse = (RentHouse) rentHouse_jdkProxy.getProxy();
// 执行目标类中的方法
rentHouse.toRentHouse();
Marry marry_Target = new User();
JDKProxy marry_jdkProxy = new JDKProxy(marry_Target);
Marry marry = (Marry) marry_jdkProxy.getProxy();
marry.toMarry();
System.out.println(marry.toMarry2());
}
}
CGLIB动态代理利用动态继承实现代理。
两者的区别:
- JDK动态代理实现接口,Cglib动态代理利用继承思想。
- JDK动态代理执行效率高于CGLIB