标签:引入 asp 不同的 ognl 多个 cte 压缩 优秀 业务逻辑层
摘要:这部分包括了Spring、Spring MVC以及Spring和其它框架整合以及測试相关的内容,除此之外还包括了大型站点技术架构相关面试内容。
151. Spring中的BeanFactory和ApplicationContext有什么联系?
答:Spring通过配置文件描写叙述Bean以及Bean之间的依赖关系。利用Java的反射机制实现Bean的实例化,并建立Bean之间的依赖关系,在此基础上,Spring的IoC容器还提供了Bean实例缓存、生命周期管理、Bean实例代理、事件公布、资源装载等高级服务。BeanFactory是Spring框架最核心的接口。它提供了IoC容器的配置机制。ApplicationContext建立在BeanFactory之上。提供了很多其它面向应用的功能,包含对国际化和框架事件体系的支持。
通常将BeanFactory称为IoC容器。而ApplicationContext称为应用上下文。前者更倾向于Spring本身。后者更倾向于开发人员,因此被使用得很多其它。
【补充】反射(reflection)又叫自省(introspection),是获得对象或类型元数据的方法,Java反射机制能够在执行时推断对象所属的类。在执行时构造随意一个类的对象。在执行时获得一个类的属性和方法,在执行时调用对象的方法,或者生成动态代理。
在Java中,能够通过类的Class对象获得类的构造器、属性、方法等类的元数据。还能够訪问这些属性或调用这些方法,和反射相关的类还包含:
通过Class对象的getConstructors方法能够获得类的全部构造器的数组。Java 5以后的版本号还能够通过getConstrcutor(Class... parameterTypes)获得拥有特定參数的构造器对象。Constructor对象的一个主要方法是newInstance,通过该方法能够创建一个类的实例。
通过Class对象的getDeclaredMethods方法能够获得全部方法的数组,Java 5以后的版本号还能够通过getDeclaredMethod(String name, Class... parameterTypes)获得特定签名的方法,当中name是方法名,可变參数代表方法的參数列表。Method对象最重要的方法是invoke(Object obj, Object[] args),当中obj是调用该方法的目标对象。args是传给方法的參数,这样就能够调用指定对象的方法。此外,Method对象还包含下面重要方法:
通过getDeclaredField(String name)则能够获取某个特定名称的属性。Field对象最重要的方法是set(Object obj, Object value),当中obj是目标对象,而value是要赋给属性的值。
除此之外,Java还提供了Package类用于包的反射,Java 5以后的版本号还提供了AnnotationElement类用于注解的反射。总之,Java的反射机制保证了能够通过编程的方式訪问目标类或对象的全部元素,对于被private和protected訪问修饰符修饰的成员。仅仅要JVM的安全机制同意,也能够通过反射进行调用。以下是一个反射的样例:
Car.java
package com.lovo; public class Car { private String brand; private int currentSpeed; private int maxSpeed; public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public void run() { currentSpeed += 10; System.out.println(brand + " is running at " + currentSpeed + " km/h"); if(currentSpeed > maxSpeed) { System.out.println("It‘s dangerous!"); } } }
CarTest.java
package com.lovo; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class CarTest { public static void main(String[] args) throws Exception { Constructor<Car> con = Car.class.getConstructor(String.class, int.class); Car myCar = (Car) con.newInstance("Benz", 280); Method m = myCar.getClass().getDeclaredMethod("run"); for(int i = 0; i < 10; i++) { m.invoke(myCar); } Field f1 = myCar.getClass().getDeclaredField("maxSpeed"); Field f2 = myCar.getClass().getDeclaredField("brand"); f1.setAccessible(true); f1.set(myCar, 80); f2.setAccessible(true); f2.set(myCar, "QQ"); m.invoke(myCar); } }
152. Spring中Bean的作用域有哪些?
答:在Spring的早期版本号中,仅有两个作用域:singleton和prototype。前者表示Bean以单例的方式存在;后者表示每次从容器中调用Bean时,都会返回一个新的实例,prototype通常翻译为原型。而设计模式中的创建型模式中也有一个原型模式。原型模式也是一个经常使用的模式,比如做一个室内设计软件,全部的素材都在工具箱中,而每次从工具箱中取出的都是素材对象的一个原型。能够通过对象克隆来实现原型模式。Spring 2.x中针对WebApplicationContext新增了3个作用域,各自是:request(每次HTTP请求都会创建一个新的Bean)、session(同一个HttpSession共享同一个Bean。不同的HttpSession使用不同的Bean)和globalSession(同一个全局Session共享一个Bean)。
须要指出的是:单例模式和原型模式都是重要的设计模式。
普通情况下。无状态或状态不可变的类适合使用单例模式。在传统开发中,由于DAO持有Connection这个非线程安全对象因而没有使用单例模式;但在Spring环境下。全部DAO类对能够採用单例模式,由于Spring利用AOP和Java API中的ThreadLocal对非线程安全的对象进行了特殊处理。
【补充】ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal。顾名思义是线程的一个本地化对象。当工作于多线程中的对象使用ThreadLocal维护变量时。ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。所以每个线程都能够独立的改变自己的副本,而不影响其它线程所相应的副本。从线程的角度看,这个变量就像是线程的本地变量。
ThreadLocal类很easy好用,仅仅有四个方法。能用上的也就是以下三个方法:
ThreadLocal是怎样做到为每个线程维护一份独立的变量副本的呢?在ThreadLocal类中有一个Map,键为线程对象。值是其线程相应的变量的副本,自己要模拟实现一个ThreadLocal类事实上并不困难,代码例如以下所看到的:
package com.lovo; import java.util.Collections; import java.util.HashMap; import java.util.Map; public class MyThreadLocal<T> { private Map<Thread, T> map = Collections.synchronizedMap(new HashMap<Thread, T>()); public void set(T newValue) { map.put(Thread.currentThread(), newValue); } public T get() { return map.get(Thread.currentThread()); } public void remove() { map.remove(Thread.currentThread()); } }
答:
Spring仅支持方法的连接点。
Spring採用了动态代理织入,而AspectJ採用了编译期织入和类装载期织入的方式。
【补充】代理模式是GoF提出的23种设计模式中最为经典的模式之中的一个,代理模式是对象的结构模式,它给某一个对象提供一个代理对象。并由代理对象控制对原对象的引用。简单的说,代理对象能够完毕比原对象很多其它的职责,当须要为原对象加入横切关注功能时。就能够使用原对象的代理对象。我们在打开Office系列的Word文档时,假设文档中有插图,当文档刚载入时,文档中的插图都仅仅是一个虚框占位符,等用户真正翻到某页要查看该图片时,才会真正载入这张图,这事实上就是对代理模式的使用。取代真正图片的虚框就是一个虚拟代理;Hibernate的load方法也是返回一个虚拟代理对象,等用户真正须要訪问对象的属性时。才向数据库发出SQL语句获得真实对象。
代理模式的类图例如以下所看到的:
以下用一个找枪手代考的样例演示代理模式的使用:
package com.lovo; /** * 參考人员接口 */ public interface Candidate { /** * 答题 */ public void answerTheQuestions(); }
package com.lovo; /** * 懒学生 */ public class LazyStudent implements Candidate { private String name; // 姓名 public LazyStudent(String name) { this.name = name; } @Override public void answerTheQuestions() { // 懒学生仅仅能写出自己的名字不会答题 System.out.println("姓名: " + name); } }
package com.lovo; /** * 枪手 * */ public class Gunman implements Candidate { private Candidate target; // 被代理对象 public Gunman(Candidate target) { this.target = target; } @Override public void answerTheQuestions() { // 枪手要写上代考的学生的姓名 target.answerTheQuestions(); // 枪手要帮助懒学生答题并交卷 System.out.println("奋笔疾书正确答案"); System.out.println("交卷"); } }
package com.lovo; public class ProxyTest1 { public static void main(String[] args) { Candidate c = new Gunman(new LazyStudent("王小二")); c.answerTheQuestions(); } }
从JDK 1.3開始。Java提供了动态代理技术,同意开发人员在执行时创建接口的代理实例,主要包含Proxy类和InvocationHandler接口。
以下的样例使用动态代理为ArrayList编写一个代理。在加入和删除元素时,在控制台打印加入或删除的元素以及ArrayList的大小:
package com.lovo; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.List; public class ListProxy<T> implements InvocationHandler { private List<T> target; public ListProxy(List<T> target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object retVal = null; System.out.println("[" + method.getName() + ": " + args[0] + "]"); retVal = method.invoke(target, args); System.out.println("[size=" + target.size() + "]"); return retVal; } }
package com.lovo; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; public class ProxyTest2 { @SuppressWarnings("unchecked") public static void main(String[] args) { List<String> list = new ArrayList<String>(); Class<?> clazz = list.getClass(); ListProxy<String> myProxy = new ListProxy<String>(list); List<String> newList = (List<String>) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), myProxy); newList.add("apple"); newList.add("banana"); newList.add("orange"); newList.remove("banana"); } }
使用Java的动态代理有一个局限性就是代理的类必需要实现接口,尽管面向接口编程是每一个优秀的Java程序都知道的规则。但现实往往不尽如人意。对于没有实现接口的类怎样为其生成代理呢?继承!
继承是最经典的扩展已有代码能力的手段,尽管继承经常被刚開始学习的人滥用。但继承也经常被进阶的程序猿忽视。
CGLib採用很底层的字节码生成技术,通过为一个类创建子类来生成代理。它弥补了Java动态代理的不足,因此Spring中动态代理和CGLib都是创建代理的重要手段,对于实现了接口的类就用动态代理为其生成代理类,而没有实现接口的类就用CGLib通过继承的方式为其创建代理。
154. Spring中自己主动装配的方式有哪些?
答:
155. Spring中怎样使用注解来配置Bean?有哪些相关的注解?
答:首先须要在Spring配置文件里添加例如以下配置:
<context:component-scan base-package="org.example"/>
156. Spring支持的事务管理类型有哪些?你在项目中使用哪种方式?
答:Spring支持编程式事务管理和声明式事务管理。很多Spring框架的用户选择声明式事务管理,由于这样的方式和应用程序的关联较少。因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理。虽然在灵活性方面它弱于编程式事务管理(编程式事务同意你通过代码控制业务)。
157. 怎样在Web项目中配置Spring的IoC容器?
答:假设须要在Web项目中使用Spring的IoC容器。能够在Web项目配置文件web.xml中做出例如以下配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
158. 怎样在Web项目中配置Spring MVC?
答:要使用Spring MVC须要在Web项目配置文件里配置其前端控制器DispatcherServlet,例如以下所看到的:
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
【注意】上面的配置中使用了*.html的后缀映射,这样做一方面不能够通过URL判断採用了何种server端的技术,还有一方面能够欺骗搜索引擎,由于搜索引擎不会搜索动态页面。这样的做法能够称为伪静态化。
159. Spring MVC的工作原理是如何的?
答:Spring MVC的工作原理例如以下图所看到的:
当然,在这个地方Spring会通过HandlerAdapter对该处理器进行封装,HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
160. 怎样在Spring IoC容器中配置数据源?
答:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/>
161. 怎样配置配置事务增强?
答:
<?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" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- this is the service object that we want to make transactional --> <bean id="fooService" class="x.y.service.DefaultFooService"/> <!-- the transactional advice (what ‘happens‘; see the <aop:advisor/> bean below) --> <tx:advice id="txAdvice" transaction-manager="txManager"> <!-- the transactional semantics... --> <tx:attributes> <!-- all methods starting with ‘get‘ are read-only --> <tx:method name="get*" read-only="true"/> <!-- other methods use the default transaction settings (see below) --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- ensure that the above transactional advice runs for any execution of an operation defined by the FooService interface --> <aop:config> <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> </aop:config> <!-- don‘t forget the DataSource --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> <property name="username" value="scott"/> <property name="password" value="tiger"/> </bean> <!-- similarly, don‘t forget the PlatformTransactionManager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- other <bean/> definitions here --> </beans>
162. 选择使用Spring框架的原因(Spring框架为企业级开发带来的优点)?
答:能够从下面几个方面作答:
163. 依赖注入的方式以及你在项目中的选择?
答:依赖注入能够通过setter方法注入(设值注入)、构造器注入和接口注入三种方式来实现,Spring支持setter注入和构造器注入,通常使用构造器注入来注入必须的依赖关系。对于可选的依赖关系。则setter注入是更好的选择,setter注入须要类提供无參构造器或者无參的静态工厂方法来创建对象。
164. 提供Spring IoC容器配置元数据的方式?
答:
package com.lovo.bean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class Person { private String name; private int age; @Autowired private Car car; public Person(String name, int age) { this.name = name; this.age = age; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } }
package com.lovo.bean; import org.springframework.stereotype.Component; @Component public class Car { private String brand; private int maxSpeed; public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } }
package com.lovo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.lovo.bean.Car; import com.lovo.bean.Person; @Configuration public class AppConfig { @Bean public Car car() { return new Car("Benz", 320); } @Bean public Person person() { return new Person("Somnus", 34); } }
package com.lovo.test; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.lovo.bean.Person; import com.lovo.config.AppConfig; class Test { public static void main(String[] args) { // TWR (Java 7+) try(ConfigurableApplicationContext factory = new AnnotationConfigApplicationContext(AppConfig.class)) { Person person = factory.getBean(Person.class); System.out.println(person); } } }
答:
166. 阐述Spring框架中Bean的生命周期?
答:
167. 依赖注入时怎样注入集合属性?
答:能够在定义Bean属性时。通过<list>/<set>/<map>/<props>分别为其注入列表、集合、映射和键值都是字符串的映射属性。
168. Spring中的自己主动装配有哪些限制?
答:
169. 和自己主动装配相关的注解有哪些?
答:
170. 怎样使用HibernateDaoSupport整合Spring和Hibernate?
答:
171. 你是怎样理解“横切关注”这个概念的?
答:“横切关注”是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的。没有必定的联系,可是差点儿全部的业务逻辑都会涉及到这些关注功能。通常,事务、日志、安全性等关注就是应用中的横切关注功能。
172. 怎样理解Spring AOP中Advice这个概念?
答:Advice在国内的非常多书面资料中都被翻译成“通知”,可是非常显然这个翻译无法表达其本质,有少量的读物上将这个词翻译为“增强”,这个翻译是对Advice较为准确的诠释,我们通过AOP将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增强。这样的增强能够是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。
173. 在Web项目中怎样获得Spring的IoC容器?
答:
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
174. Spring MVC怎样对RESTful风格提供支持?
答:假设不了解RESTful能够看看百度百科的解说。关于这个问题,能够看看blogjava上的还有一个帖子。
175. 大型站点在架构上应当考虑哪些问题?
答:
计算机网络的开放系统互联參考模型(OSI/RM)和Internet的TCP/IP模型都是分层结构,大型站点的软件系统也能够使用分层的理念将其分为持久层(提供数据存储和訪问服务)、业务层(处理业务逻辑。系统中最核心的部分)和表示层(系统交互、视图展示)。
须要指出的是:(1)分层是逻辑上的划分,在物理上能够位于同一设备上也能够在不同的设备上部署不同的功能模块,这样能够使用很多其它的计算资源来应对用户的并发訪问;(2)层与层之间应当有清晰的边界。这样分层才有意义。才更利于软件的开发和维护。
使用缓存是站点优化的第一定律。我们通常说的CDN、反向代理、热点数据都是对缓存技术的使用。
176. 你用过的站点前端优化的技术有哪些?
答:
177. 你使用过的应用server优化技术有哪些?
答:
缓存主要用来存放那些读写比非常高、变化非常少的数据。这样应用程序读取数据时先到缓存中读取。假设没有或者数据已经失效再去訪问数据库或文件系统。并依据拟定的规则将数据写入缓存。对站点数据的訪问也符合二八定律(Pareto分布,幂律分布)。即80%的訪问都集中在20%的数据上,假设能够将这20%的数据缓存起来,那么系统的性能将得到显著的改善。当然,使用缓存须要解决下面几个问题:(1)频繁改动的数据;(2)数据不一致与脏读。(3)缓存雪崩(能够採用分布式缓存server集群加以解决。Memcached是广泛採用的解决方式,它是一种互不通信的集中式管理的分布式缓存方案,能够从http://memcached.org/了解到关于Memcached的相关信息)。(4)缓存预热;(5)缓存穿透(恶意持续请求不存在的数据)。
电商站点在进行促销活动时,能够将用户的订单请求存入消息队列。这样能够抵御大量的并发订单请求对系统和数据库的冲击。
眼下。绝大多数的电商站点即便不进行促销活动,订单系统都採用了消息队列来处理。
使用ThreadLocal将对象与线程绑定也是非常好的做法,这一点在前面已经探讨过了。
178. 什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?
答:
CSRF的原理是利用浏览器的Cookie或server的Session,盗取用户身份。其原理例如以下图所看到的。防范CSRF的主要手段是识别请求者的身份,主要有下面几种方式:(1)在表单中加入令牌(token);(2)验证码。(3)检查请求头中的Referer(前面提到防图片盗链接也是用的这样的方式)。令牌和验证都具有一次消费性的特征,因此在原理上一致的。可是验证码是一种糟糕的用户体验,不是必要的情况下不要轻易使用验证码,眼下非常多站点的做法是假设在短时间内多次提交一个表单未获得成功后才要求提供验证码,这样会获得较好的用户体验。
企业级防火墙的架设应当有两级防火墙。Webserver和部分应用server能够架设在两级防火墙之间的DMZ,而数据和资源server应当架设在第二级防火墙之后。例如以下图所看到的。
以下两张图分别展示了贫血模型和充血模型的分层架构。
也就是说在设计业务逻辑接口的时候。每一个方法相应着用户的一个操作,这样的模式有下面几个有点:
TDD能够在多个层级上应用,包含单元測试(測试一个类中的代码)、集成測试(測试类之间的交互)、系统測试(測试执行的系统)和系统集成測试(測试执行的系统包含使用的第三方组件)。TDD的实施步骤是:红(失败測试) --- 绿(通过測试) --- 重构。
关于实施TDD的具体步骤请參考还有一篇文章《測试驱动开发之初窥门径》。
在使用TDD开发时。常常会遇到须要被測对象须要依赖其它子系统的情况,可是你希望将測试代码跟依赖项隔离。以保证測试代码只针对当前被測对象或方法展开。这时候你须要的是測试替身。測试替身能够分为四类:
标签:引入 asp 不同的 ognl 多个 cte 压缩 优秀 业务逻辑层
原文地址:http://www.cnblogs.com/cynchanpin/p/6847946.html